jQuery ajax跨域请求

来源:互联网 发布:淘宝怎么同步付款 编辑:程序博客网 时间:2024/03/29 19:25
jQuery跨域请求,是为了解决在浏览器安全机制(同源策略:Same Origin Policy)的限制下,无法获取非同源数据的一种方式。
所谓同源是指协议、域名、端口相同。


jQuery提供两种跨域方法:

1.jQuery.ajax:

使用ajax方法跨域请求,需要将dataType设置为"jsonp":

var url = "http://cms.yhd.com/cmsPage/get***ForJsonp.do";jQuery.ajax({url: url,//实际上访问的地址为:http://cms.yhd.com/cmsPage/get***ForJsonp.do?id=1&callback123=getJsonpCallback456data:{id:1},//必须为key/value的形式dataType: "jsonp",jsonp: "callback123",//存储jsonp回调函数名的参数(默认值为callback)jsonpCallback: "getJsonpCallback456",//jsonp回调函数名。如果不指定,jQuery会自动生成随机函数名,这样的话url每次都不同,也就无法缓存cache: true,timeout: 2000,success: function (rs) {alert("success");},error: function (rs) {alert("error");}});

执行以上ajax请求,会得到如下形式的返回结果(数据不是真实的):

getJsonpCallback456({"pageId":55778,"pageName":"测试页面"});
可以看出,返回结果中含有指定的jsonp回调函数getJsonpCallback456,并将响应的json数据作为参数传入此函数。

如果将以上请求改为json形式,此时只能访问同源下的数据,代码为:

var url = "http://cms.yhd.com/cmsPage/get***ForJson.do";jQuery.ajax({url: url,//实际上访问的地址为:http://cms.yhd.com/cmsPage/get***ForJson.do?id=1data:{id:1},dataType: "json",cache: true,timeout: 2000,success: function (rs) {alert("success");},error: function (rs) {alert("error");}});

那么返回的结果形式将为:
{"pageId":55778,"pageName":"测试页面"}
即json请求直接将json格式的数据进行返回,这是和jsonp的形式不同的地方。


2.jQuery.getJSON:

getJSON方法是jQuery专门为请求json数据而设置的,同时也支持跨域请求:

var url = "http://cms.yhd.com/cmsPage/get***ForJsonp.do";$.getJSON(url, function(rs) {  alert(rs.pageId);  }); 

以上代码只能访问同源数据,因为没有添加回调函数。只有在url中加上回调函数,才可以进行跨域:

var url = "http://cms.yhd.com/cmsPage/get***ForJsonp.do?callback=?";$.getJSON(url, function(rs) {  alert(rs.pageId);  });

这种情况下,服务器返回的数据形式为:
jQuery1113023920281590304815_1491998237482({"pageId":55778,"pageName":"测试页面"})
那么这个jQuery1113023920281590304815_1491998237482哪里来的呢?我们查看具体请求的url,发现url变为了:
http://cms.yhd.com/cmsPage/get***ForJsonp.do?callback=jQuery1113023920281590304815_1491998237482
也就是说jQuery会把?自动替换为一个具体的回调函数名称。


注:以上两种方法的请求类型均为默认的"GET","POST"类型是不支持跨域的。

跨域操作,不仅需要客户端采用如上两种方式(当然还有其他方式)请求数据,同时也需要服务器端的支持:
String json = "{'pageId':55778,'pageName':'测试页面'}";
String cb = context.Request["callback"]; 
context.Response.Write(cb + "(" + json + ")"); 
这样,其他域名才能使用跨域的方式请求此服务器的数据。

而如果服务器端不做这些处理,仅仅是将json数据返回,那么客户端使用jsonp的形式,是请求不到数据的。


3.记录一个实际项目中碰到的问题:

融合项目时,页面中精准化推荐的部分是调用JD接口来获取的。这个接口支持jsonp,那好办,就用ajax获取呗,第一版代码如下:

var url = "//xxx.jd.com/xxx?lid=1&lim=5&ec=utf-8&sku=1234&callback=?";$.ajax({url: url,dataType: 'jsonp',timeout: 2000,success: function (rs) {//业务逻辑},error: function () {console.log("pms recommend error, the type is: " + type);}});

写好后调试,发现有时可获取到数据,有时接口报400,400代表着语法格式错误,服务器无法理解此请求,这就奇怪了。。。

经过仔细排查,最后发现是回调函数的名字出了问题。上面代码的url中callback=?,也就意味着回调函数的名字是由jQuery自动生成的。而由jQuery自动生成的名字,是有可能带有下划线的。一旦url中带有下划线,接口接有大概率报400。

问提找到,就好解决了,既然jQuery自动生成的回调名有下划线,那我就把回调名自己定义了,第二版代码如下:

var url = "//xxx.jd.com/xxx?lid=1&lim=5&ec=utf-8&sku=1234&callback=?";$.ajax({url: url,dataType: 'jsonp',jsonpCallback: "PmsCallback",timeout: 2000,success: function (rs) {//业务逻辑},error: function () {console.log("pms recommend error, the type is: " + type);}});

加上了jsonpCallback: "PmsCallback",这样回调函数名就被固定为PmsCallback,也就解决了400的问题。

但是这时问题又来了,因为我页面有4个精准化推荐栏目,都是在页面打开时加载的。这样修改代码后,经常只有一两个栏目能显示出数据。找原因,找问题,最后发现是回调名写死后,4次请求成功后执行的回调函数名称相同,只是参数不同而已。这也势必导致后面的会覆盖掉前面的回调处理,所以有的栏目没有数据。那咋办呢?改回调呗。第三版代码如下:

var url = "//xxx.jd.com/xxx?lid=1&lim=5&ec=utf-8&sku=1234&callback=?";$.ajax({url: url,dataType: 'jsonp',jsonpCallback: "PmsCallback" + type, //增加了typetimeout: 2000,success: function (rs) {//业务逻辑},error: function () {console.log("pms recommend error, the type is: " + type);}});

这里在回调函数名称后加了个type,这个type是指不同的推荐位名称,它是函数调用处传过来的参数,4个推荐位的名称是不同的。如果没这个type,可用其他变量代替,或者加1 2 3 4 也是可以的。这样,4次请求的回调名就不同了,也就不会出现后面的回调覆盖掉前面的情况了。

OK,问题解决。



1 0