项目中遇到了要使用跨域的post请求,在IE10以下遇到了坑
跨域使用的是CORS
1、前端脚本
<script>2、后端服务端controller层
function tests(){
//请求类型 为了满足IE8,IE9通过cors跨域请求
var contentType ="application/x-www-form-urlencoded; charset=utf-8";
//var contentType ="text/plain; charset=utf-8";
//contentType ="application/json; charset=utf-8",
/* if(window.XDomainRequest){ //for IE8,IE9
contentType = "text/plain";
} */
/* var param={};
var sss = "";
for(var i=0;i<1000;i++){
sss+="我";
}
param.ZHAA03A015=sss;
param.ZHAA03A025=sss;
param.ZHAA03A035=sss;
param.ZHAA03A045=sss;
param.ZHAA03A055=sss;
param.ZHAA03A065=sss;
param.ZHAA03A075=sss;
param.ZHAA03A085=sss;
param.ZHAA03A095=sss;
param.ZHAA03A010=sss; */
//param.ZHAA03A055="430723";
var params={};
params.ZHAA03A055="430723";
var ss = JSON.stringify(params);
jQuery.support.cors = true;
$.ajax({
type:'post',
dataType :'json',
contentType:contentType,
url:"http://192.168.88.55:8080/ys.fwgl/service/ZHAA03A_queryWybh/servicePostTest",
data:{"params":ss},
success:function(data){
var result=data.result;
var datas = result.datas;
for(var i=0;i<datas.length;i++){
alert(datas[i].ZHAA03A010);
}
},
error:function(data){
alert("error:"+data.status);
}
});
}
</script>
@RequestMapping(value = "/{serviceCode}/servicePostTest", method = RequestMethod.POST)IE10以下版本post 方式提交数据获取参数要使用 @RequestBody方式获取,
@ResponseBody
public ResultObject servicePostTest(@PathVariable String serviceCode,HttpServletRequest req,@RequestBody String params) {
String param1 = req.getParameter("params");
System.out.println("===============1================"+param1);
System.out.println("===============2================"+params);
logger.error("===============POST================"+param1);
logger.error("===============POST================"+params);
String ssString = params.substring(6);
System.out.println("=============截取过后==3================"+ssString);
try {
String searchtext=java.net.URLDecoder.decode(ssString,"UTF-8");
System.out.println("=============解码过后==4================"+searchtext);
return new ResultObject();
} catch (UnsupportedEncodingException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
return new ResultObject(e1.getMessage(),null,false);
}
}
IE就是坑
$.ajax contenType是appliation/json的时候,spring mvc后台无法接受data参数
做Redis监控工具的时候,发现$.ajax contenType是appliation/json的时候,在后台用spring mvc的@Requestparam注解接收参数,始终接收不到。
前台代码:
$.ajax({
url : "${ctx}/rediscluster/delete.do",
data : JSON.stringify (' {"rname":rname}'),
type : "post",
dataType:"text",
contentType : "application/json",
success : function(data) {
if(data == 'OK'){
window.location = "${ctx}/system/redis/nodesmanager.jsp";
}
}
});
后台的主要代码:
@ResponseBody
@RequestMapping(value="/delete.do",produces = {"application/json;charset=utf-8"})
public String deletenode(@RequestParam("rname")String rname) throws GeneralException{
SqlSession sqlsession = sqlsessionfactory.openSession();
在@RequestParam("rname")String rname接收参数的时候,总是报错:String parameter ' rname ' is not present,前台返回400.又用另一种方式,request.getParameter("rname")来获得,同样发现,始终是null.
网上找了一些资料后,将后台代码修改如下,问题解决:
@ResponseBody
@RequestMapping(value="/delete.do",produces = {"application/json;charset=utf-8"})
public String deletenode(@RequestBodyString rname) throws GeneralException{
SqlSession sqlsession = sqlsessionfactory.openSession();
这种方式可以接收参数,但是request.getParameter("rname")任然不行。
后来发现原因如下:
@RequestParam 底层是通过request.getParameter方式获得参数的,也就是说,@RequestParam 和request.getParameter是同一回事。因为使用request.getParameter()方式获取参数,可以处理get 方式中queryString的值,也可以处理post方式中 body data的值,所以,@RequestParam可以处理get 方式中queryString的值,也可以处理post方式中 body data的值。@RequestParam用来处理Content-Type: 为 application/x-www-form-urlencoded编码的内容,提交方式GET、POST。
注意:
@RequestParam用来处理ContentType: 为 application/x-www-form-urlencoded编码的内容
@RequestBody
该注解常用来处理Content-Type: 不是application/x-www-form-urlencoded编码的内容,例如application/json, application/xml等;
@RequestBody接收的是一个Json对象的字符串,而不是一个Json对象。在ajax请求往往传的都是Json对象,用JSON.stringify(data)的方式就能将对象变成字符串。
HTTP请求中,如果是get请求,那么表单参数以name=value&name1=value1的形式附到url的后面,如果是post请求,那么表单参数是在请求体中,也是以name=value&name1=value1的形式在请求体中。通过chrome的开发者工具可以看到如下(这里是可读的形式,不是真正的HTTP请求协议的请求格式):
get请求:
Post请求:
这里要注意post请求的Content-Type为application/x-www-form-urlencoded,参数是在请求体中,即上面请求中的Form Data。
在servlet中,可以通过request.getParameter(name)的形式来获取表单参数。
而如果使用原生AJAX POST请求的话:
通过chrome的开发者工具看到请求头如下:
注意请求的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请求)的处理代码如下:
从上面代码可以看出,Content-Type不是application/x-www-form-urlencoded的POST请求是不会读取请求体数据和进行相应的参数处理的,即不会解析表单数据来放到request parameter map中。所以通过request.getParameter(name)是获取不到的。
那么这样提交的参数我们该怎么获取呢?
当然是使用最原始的方式,读取输入流来获取了,如下所示:
当然,设置了application/x-www-form-urlencoded的POST请求也可以通过这种方式来获取。
所以,在使用原生AJAX POST请求时,需要明确设置Request Header,即:
另外,如果使用jQuery,我使用1.11.0这个版本来测试,$.ajax post请求是不需要明确设置这个请求头的,其他版本的本人没有亲自测试过。相信在1.11.0之后的版本也是不需要设置的。不过之前有的就不一定了。这个没有测试过。
2015-04-17后记:
最近在看书时才真正搞明白,服务器为什么会对表单提交和文件上传做特殊处理,因为表单提交数据是名值对的方式,且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,这时服务器就不知道怎么解析数据了,所以才只能通过获取原始数据流的方式来进行解析请求数据。