post请求参数问题
from:https://www.cnblogs.com/btgyoyo/p/6141480.html
jQuery的ajax方法和post方法分别发送请求,在后台Servlet进行处理时结果是不一样的,比如用$.ajax方法发送请求时(data参数是一个JSON.stringify()处理后的字符串,而不是一个JSON对象),servlet里可以这样使用Gson来解析:
new Jsonparser().parse(request.getReader())
但此时是不可用request.getParam(key) 来取值的。
如果用$.post方法来发送请求(data参数是一个JSON对象,而不要再用JSON.stringify()处理为字符串了),结果恰恰相反。
在Chrome中调试发现,$.ajax发送的请求显示在request payload下面,而使用$.post方法发送的请求显示在form data下面。有什么区别呢?
关键就是设置Content-type这个Header为application/x-www-form-urlencoded,实际上对于常规的HTML页面上的form的Content-type默认就是这个值。
这里要注意post请求的Content-Type为application/x-www-form-urlencoded,参数是在请求体中,即上面请求中的Form Data。
在servlet中,可以通过request.getParameter(name)的形式来获取表单参数。
而如果使用原生AJAX POST请求的话:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
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的开发者工具看到请求头如下
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
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请求)的处理代码如下:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
|
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)是获取不到的。
那么这样提交的参数我们该怎么获取呢?
当然是使用最原始的方式,读取输入流来获取了,如下所示:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
|
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");
post请求参数问题的更多相关文章
- nodejs进阶(5)—接收请求参数
1. get请求参数接收 我们简单举一个需要接收参数的例子 如果有个查找功能,查找关键词需要从url里接收,http://localhost:8000/search?keyword=地球.通过前面的进 ...
- 学习SpringMVC——如何获取请求参数
@RequestParam,你一定见过:@PathVariable,你肯定也知道:@QueryParam,你怎么会不晓得?!还有你熟悉的他(@CookieValue)!她(@ModelAndView) ...
- 限制action所接受的请求方式或请求参数
原文:http://www.cnblogs.com/liukemng/p/3726897.html 2.限制action所接受的请求方式(get或post): 之前我们在HelloWorldContr ...
- SpringMVC RequestMapping & 请求参数
SpringMVC 概述 Spring 为展现层提供的基于 MVC 设计理念的优秀的Web 框架,是目前最主流的 MVC 框架之一 Spring3.0 后全面超越 Struts2,成为最优秀的 MVC ...
- JS-获取URL请求参数
前言:原来做过一个项目,需要实现一个页面打印的功能,由于项目中使用了AngularJS+Bootstrap等前端框架,需要打印的页面又在弹出框中,使用了Bootstrap的模态框后发现打印的效果不太好 ...
- web基础---->request的请求参数分析
当contentType为application/json的时候,在servlet中通过request.getParameter得到的数据为空.今天我们就java的请求,分析一下request得到参数 ...
- GET请求参数为中文时乱码分析
问题描述 近期做任务时,跟后端联调时遇到一个问题,前端发送get请求,当参数值有中文时,请求失败,请求参数变为乱码.(ps:一般当参数有中文时,很少使用get请求,而是使用post请求来传输数据,请求 ...
- springmvc请求参数获取的几种方法
1.直接把表单的参数写在Controller相应的方法的形参中,适用于get方式提交,不适用于post方式提交. /** * 1.直接把表单的参数写在Controller相应的方法的形参中 * @pa ...
- Struts2请求参数校验
校验的分类 客户端数据校验 和 服务器端数据校验 客户端数据校验 ,通过JavaScript 完成校验 (改善用户体验,使用户减少出错 ) 服务器数据校验 ,通过Java代码 完成校验 struts2 ...
- Action处理请求参数
第一种 :Action 本身作为model对象,通过成员setter封装 (属性驱动 ) 第一种方式:<br> <form action="${pageContext.re ...
随机推荐
- C语言事实上不简单:sizeof
问:C语言中一共同拥有多少个keyword? 答:32个. 答不上来的没关系.非常正常.我们玩的是程序的艺术.而不是背数字. 只是这个特殊的数字1<<5也是非常好记的-.-. 问:size ...
- EBS R12视图打不到数据
兩個原因引起的,一個是語言,一個是oualter session set nls_language ='AMERICAN';alter session set nls_language='SIMPLI ...
- Android防止进程被第三方软件杀死
http://blog.csdn.net/wangliang198901/article/details/12342845 http://stackoverflow.com/questions/385 ...
- ios webview下纯JS实现长按
app,其中有长按LI列表弹出菜单,只要清楚五个方法就行:ontouchstart.ontouchmove.ontouchend.setTimeout.clearTimeout 1.首先在我们按下手指 ...
- qt不能调试
在F5执行qt的调试时,提示:unknown debugger type "No engine" 需要下载debug调试工具,win7的下载位于:https://www.micro ...
- python3用BeautifulSoup抓取图片地址
# -*- coding:utf-8 -*- #python 2.7 #XiaoDeng #http://tieba.baidu.com/p/2460150866 #抓取图片地址 from bs4 i ...
- iOS APP 安全测试
1.ipa包加壳 首先,我们可以通过iTunes 下载 AppStore的ipa文件(苹果 把开发者上传的ipa包 进行了加壳再放到AppStore中),所以我们从AppStore下载的ipa都是加壳 ...
- AirServer for Mac(Airplay 终端实用工具)破解版安装
1.软件简介 AirServer 是一款 Mac 上的 AirPlay 终端,通过这款软件,利用 AirPlay 技术,iPhone 或 iPad 就可以无线连接到 Mac 上,不需要在 iPh ...
- Android websock 应用
websocket 在实际的应用中不仅仅能做聊天应用,还可以利用websocket长连接保持数据的实时更新以及信息的推送. websocket 的实现的关键点 第一个:首先需要引入 java-webs ...
- 关于c语言的左移运算
对于任意w位的二进制,进行k位的移动时,真实的位移量为k mod w 32bit的例子 1 << 1 结果2 1 mod 32 => 11 << 32 结果1 32 mo ...