jQuery ajax跨域请求

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=getJsonpCallback456
	data:{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=1
	data:{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, //增加了type
	timeout: 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
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值