转载至 http://blog.csdn.net/mhmyqn/article/details/25561535

最近在写接收第三方的json数据, 因为对java不熟悉,有时候能通过request能接到,有时候接不到,还不知道为什么,很是郁闷,只是大体知道问题出在传输的content_Type上, 痛定思痛,上网学习一下到底这个东西是干什么的,在网上找到一篇文章讲的比较透彻,在这儿备注以做学习

HTTP请求中,如果是get请求,那么表单参数以name=value&name1=value1的形式附到url的后面,如果是post请求,那么表单参数是在请求体中,也是以name=value&name1=value1的形式在请求体中。通过chrome的开发者工具可以看到如下(这里是可读的形式,不是真正的HTTP请求协议的请求格式):

get请求:

RequestURL:http://127.0.0.1:8080/test/test.do?name=mikan&address=street
Request Method:GET
Status Code:200 OK Request Headers
Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Encoding:gzip,deflate,sdch
Accept-Language:zh-CN,zh;q=0.8,en;q=0.6
AlexaToolbar-ALX_NS_PH:AlexaToolbar/alxg-3.2
Connection:keep-alive
Cookie:JSESSIONID=74AC93F9F572980B6FC10474CD8EDD8D
Host:127.0.0.1:8080
Referer:http://127.0.0.1:8080/test/index.jsp
User-Agent:Mozilla/5.0 (Windows NT 6.1)AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.149 Safari/537.36 Query String Parameters
name:mikan
address:street Response Headers
Content-Length:2
Date:Sun, 11 May 2014 10:42:38 GMT
Server:Apache-Coyote/1.1

  Post请求:

RequestURL:http://127.0.0.1:8080/test/test.do
Request Method:POST
Status Code:200 OK Request Headers
Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Encoding:gzip,deflate,sdch
Accept-Language:zh-CN,zh;q=0.8,en;q=0.6
AlexaToolbar-ALX_NS_PH:AlexaToolbar/alxg-3.2
Cache-Control:max-age=0
Connection:keep-alive
Content-Length:25
Content-Type:application/x-www-form-urlencoded
Cookie:JSESSIONID=74AC93F9F572980B6FC10474CD8EDD8D
Host:127.0.0.1:8080
Origin:http://127.0.0.1:8080
Referer:http://127.0.0.1:8080/test/index.jsp
User-Agent:Mozilla/5.0 (Windows NT 6.1)AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.149 Safari/537.36 Form Data
name:mikan
address:street Response Headers
Content-Length:2
Date:Sun, 11 May 2014 11:05:33 GMT
Server:Apache-Coyote/1.1

  这里要注意post请求的Content-Type为application/x-www-form-urlencoded,参数是在请求体中,即上面请求中的Form Data。

在servlet中,可以通过request.getParameter(name)的形式来获取表单参数。

而如果使用原生AJAX POST请求的话:

function getXMLHttpRequest() {
var xhr;
if(window.ActiveXObject) {
xhr= new ActiveXObject("Microsoft.XMLHTTP");
}else if (window.XMLHttpRequest) {
xhr= new XMLHttpRequest();
}else {
xhr= null;
}
return xhr;
} function save() {
var xhr = getXMLHttpRequest();
xhr.open("post","http://127.0.0.1:8080/test/test.do");
var data = "name=mikan&address=street...";
xhr.send(data);
xhr.onreadystatechange= function() {
if(xhr.readyState == 4 && xhr.status == 200) {
alert("returned:"+ xhr.responseText);
}
};
}

  通过chrome的开发者工具看到请求头如下:

RequestURL:http://127.0.0.1:8080/test/test.do
Request Method:POST
Status Code:200 OK Request Headers
Accept:*/*
Accept-Encoding:gzip,deflate,sdch
Accept-Language:zh-CN,zh;q=0.8,en;q=0.6
AlexaToolbar-ALX_NS_PH:AlexaToolbar/alxg-3.2
Connection:keep-alive
Content-Length:28
Content-Type:text/plain;charset=UTF-8
Cookie:JSESSIONID=C40C7823648E952E7C6F7D2E687A0A89
Host:127.0.0.1:8080
Origin:http://127.0.0.1:8080
Referer:http://127.0.0.1:8080/test/index.jsp
User-Agent:Mozilla/5.0 (Windows NT 6.1)AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.149 Safari/537.36 Request Payload
name=mikan&address=street Response Headers
Content-Length:2
Date:Sun, 11 May 2014 11:49:23 GMT
Server:Apache-Coyote/1.1

  

注意请求的Content-Type为text/plain;charset=UTF-8,而请求表单参数在RequestPayload中。

那么servlet中通过request.getParameter(name)却是空。为什么呢?而这样的参数又该怎么样获取呢?

为了搞明白这个问题,查了些资料,也看了Tomcat7.0.53关于请求参数处理的源码,终于搞明白了是怎么回事。

HTTP POST表单请求提交时,使用的Content-Type是application/x-www-form-urlencoded,而使用原生AJAX的POST请求如果不指定请求头RequestHeader,默认使用的Content-Type是text/plain;charset=UTF-8。

由于Tomcat对于Content-Type multipart/form-data(文件上传)和application/x-www-form-urlencoded(POST请求)做了“特殊处理”。下面来看看相关的处理代码。

Tomcat的HttpServletRequest类的实现类为org.apache.catalina.connector.Request(实际上是org.apache.coyote.Request),而它对处理请求参数的方法为protected void parseParameters(),这个方法中对Content-Type multipart/form-data(文件上传)和application/x-www-form-urlencoded(POST请求)的处理代码如下:

protectedvoid parseParameters() {
//省略部分代码......
parameters.handleQueryParameters();// 这里是处理url中的参数
//省略部分代码......
if ("multipart/form-data".equals(contentType)) { // 这里是处理文件上传请求
parseParts();
success = true;
return;
} if(!("application/x-www-form-urlencoded".equals(contentType))) {// 这里如果是非POST请求直接返回,不再进行处理
success = true;
return;
}
//下面的代码才是处理POST请求参数
//省略部分代码......
try {
if (readPostBody(formData, len)!= len) { // 读取请求体数据
return;
}
} catch (IOException e) {
// Client disconnect
if(context.getLogger().isDebugEnabled()) {
context.getLogger().debug(
sm.getString("coyoteRequest.parseParameters"),e);
}
return;
}
parameters.processParameters(formData, 0, len); // 处理POST请求参数,把它放到requestparameter map中(即request.getParameterMap获取到的Map,request.getParameter(name)也是从这个Map中获取的)
// 省略部分代码......
} protected int readPostBody(byte body[], int len)
throws IOException { int offset = 0;
do {
int inputLen = getStream().read(body, offset, len - offset);
if (inputLen <= 0) {
return offset;
}
offset += inputLen;
} while ((len - offset) > 0);
return len;
}

  从上面代码可以看出,Content-Type不是application/x-www-form-urlencoded的POST请求是不会读取请求体数据和进行相应的参数处理的,即不会解析表单数据来放到request parameter map中。所以通过request.getParameter(name)是获取不到的。

那么这样提交的参数我们该怎么获取呢?

当然是使用最原始的方式,读取输入流来获取了,如下所示:

privateString getRequestPayload(HttpServletRequest req) {
StringBuildersb = new StringBuilder();
try(BufferedReaderreader = req.getReader();) {
char[]buff = new char[1024];
intlen;
while((len = reader.read(buff)) != -1) {
sb.append(buff,0, len);
}
}catch (IOException e) {
e.printStackTrace();
}
returnsb.toString();
}

  

当然,设置了application/x-www-form-urlencoded的POST请求也可以通过这种方式来获取。

所以,在使用原生AJAX POST请求时,需要明确设置Request Header,即:

xhr.setRequestHeader("Content-Type","application/x-www-form-urlencoded");

  另外,如果使用jquery,我使用1.11.0这个版本来测试,$.ajax post请求是不需要明确设置这个请求头的,其他版本的本人没有亲自测试过。相信在1.11.0之后的版本也是不需要设置的。不过之前有的就不一定了。这个没有测试过。

注:

服务器为什么会对表单提交和文件上传做特殊处理,因为表单提交数据是名值对的方式,且Content-Type为application/x-www-form-urlencoded,而文件上传服务器需要特殊处理,普通的post请求(Content-Type不是application/x-www-form-urlencoded)数据格式不固定,不一定是名值对的方式,所以服务器无法知道具体的处理方式,所以只能通过获取原始数据流的方式来进行解析。

jquery在执行post请求时,会设置Content-Type为application/x-www-form-urlencoded,所以服务器能够正确解析,而使用原生ajax请求时,如果不显示的设置Content-Type,那么默认是text/plain,这时服务器就不知道怎么解析数据了,所以才只能通过获取原始数据流的方式来进行解析请求数据。

[转]AJAX POST请求中参数以form data和request payload形式在servlet中的获取方式的更多相关文章

  1. AJAX POST请求中参数以form data和request payload形式在servlet中的获取方式

    转载:http://blog.csdn.net/mhmyqn/article/details/25561535 HTTP请求中,如果是get请求,那么表单参数以name=value&name1 ...

  2. AJAX POST请求中參数以form data和request payload形式在servlet中的获取方式

    HTTP请求中,假设是get请求,那么表单參数以name=value&name1=value1的形式附到url的后面,假设是post请求,那么表单參数是在请求体中,也是以name=value& ...

  3. AJAX POST请求中参数以form data和request payload形式在php中的获取方式

    一.MINE TYPE问题: php对mime type为“application/x-www-form-urlencoded”(表单提交)和“multipart/form-data”(文件上传)的P ...

  4. POST请求中参数以form data和request payload形式+清空数组方式

    测试与服务端ajax时用的dva封装的request方法,而后端怎么也拿不到参数.结果返现参数在request payload里. HTTP POST表单请求提交时:Content-Typeappli ...

  5. HTTP请求中的Form Data与Request Payload的区别

    前端开发中经常会用到AJAX发送异步请求,对于POST类型的请求会附带请求数据.而常用的两种传参方式为:Form Data 和 Request Payload. GET请求 使用get请求时,参数会以 ...

  6. HTTP 请求中的 Form Data 与 Request Payload 的区别

    HTTP 请求中的 Form Data 与 Request Payload 的区别 前端开发中经常会用到 AJAX 发送异步请求,对于 POST 类型的请求会附带请求数据.而常用的两种传参方式为:Fo ...

  7. [整理]Ajax Post请求下的Form Data和Request Payload

    Ajax Post请求下的Form Data和Request Payload 通常情况下,我们通过Post提交表单,以键值对的形式存储在请求体中.此时的reqeuest headers会有Conten ...

  8. Vue中应用CORS实现AJAX跨域,及它在 form data 和 request payload 的小坑处理

    基本概念部分(一):理解CORS 说道Vue的跨域AJAX,我想先梳理一遍CORS跨域,"跨域资源共享"(Cross-origin resource sharing),它是一个W3 ...

  9. axios 请求中的Form Data 与 Request Payload的区别

    在vue项目中使用axios发post请求时候,后台返回500. 发现是form Data 和 Request payload的问题. 后台对两者的处理方式不同,导致我们接收不到数据. 解决方案:使用 ...

随机推荐

  1. spring boot 单元测试

    Java新手 纯记录 @RunWith(SpringJUnit4ClassRunner.class) @SpringBootTest(classes = OutDemoApplication.clas ...

  2. useradd和groupadd(Linux创建用户\用户组\设置\分配用户权限\多用户远程登录权限)的使用

    前言: man useradd man  groupadd info useradd info  groupadd 都可以获取相关命令的用法信息. 个人比较喜欢读英文解释文档,没有你想象的那么comp ...

  3. 02MYSQL查询语句

    查询语句是用于将表里的数据查询出来==查询可以返回一个结果集(表) | 或者的意思   * 代表当前表的所有字段 **查询语句的语法:select *| 字段名列表 from 表名 [where 条件 ...

  4. 普通Linux用户1分钟上手vi编辑器

    *导读:普通用户只要花1分钟看第二部分即可.高级用户请忽略本文* 目录 1. 编辑器之战 2. vi的使用 2.1 vi的3个模式 2.2 vi的3个模式切换 2.3 vi最基本的命令 2.4 vi的 ...

  5. 第二次作业-分布式版本控制系统Git的安装与使用

    本次作业要求来自:https://edu.cnblogs.com/campus/gzcc/GZCC-16SE1/homework/2103 我的github远程仓库的地址:https://github ...

  6. 思科模拟器-DHCP配置

    一.如图做好以下拓扑图(下图我取消显示端口号) 二.配置最下面的四台上网终端为自动获取ip 三.配置中间的二层交换机:添加vlan,同时所有端口设为access类型并将其加入vlan中,以下以swit ...

  7. 2019软件工程第二次作业(VS2017中对C++的单元测试)

    建立工程,分别编写cpp和头文件 cpp文件中的代码如下: #include<iostream> #include"test.h" using namespace st ...

  8. 创建一个dynamics 365 CRM online plugin (五) - Images in Plugin

    Snapshots of the primary entity's attributes from database before(pre) and after (post) the core pla ...

  9. 2018-2019-2 20175202实验一《Java开发环境的熟悉》实验报告

    2018-2019-2 20175202实验一<Java开发环境的熟悉>实验报告 一.实验内容 1.使用JDK编译.运行简单的Java程序: 2.使用IDEA 编辑.编译.运行.调试Jav ...

  10. 黄聪:C#中CefSharp的简单使用

    C#中CefSharp的简单使用 https://blog.csdn.net/qq_26712977/article/details/78282995