首页 > 代码库 > js&jquery跨域详解jsonp,jquery并发大量请求丢失回调bug
js&jquery跨域详解jsonp,jquery并发大量请求丢失回调bug
URL | 说明 | 是否允许通信 |
---|---|---|
http://www.a.com/a.js http://www.a.com/b.js | 同一域名下 | 允许 |
http://www.a.com/lab/a.js http://www.a.com/script/b.js | 同一域名下不同文件夹 | 允许 |
http://www.a.com:8000/a.js http://www.a.com/b.js | 同一域名,不同端口 | 不允许 |
http://www.a.com/a.js https://www.a.com/b.js | 同一域名,不同协议 | 不允许 |
http://www.a.com/a.js http://70.32.92.74/b.js | 域名和域名对应ip | 不允许 |
http://www.a.com/a.js http://script.a.com/b.js | 主域相同,子域不同 | 不允许 |
http://www.a.com/a.js http://a.com/b.js | 同一域名,不同二级域名(同上) | 不允许(cookie这种情况下也不允许访问) |
http://www.cnblogs.com/a.js http://www.a.com/b.js | 不同域名 | 不允许 |
我们现在要解决的问题是将这些不允许变为允许。。。
JS跨域
1、为什么会有跨域?
简单的来说,在发送ajax请求的时候会遇到js跨域
大家都知道,发送ajax的时候会用到XMLHttpRequest这个对象,但是为了安全,浏览器对象做出了限制,不允许上表中的不允许情况通信。。。
所以,只要不使用XMLHttpRequest对象发送ajax请求,就不会出现跨域限制的问题。
2、不使用ajax发送请求,但是要达到局部刷新的效果怎么办?
假设请求的网页为本地的1.html
<html> <head> </head> <body> </body> </html>
动态加载js
var script = document.createElement("script"); script.type = "text/javascript"; script.src = http://www.mamicode.com/"http://bbb.com";>这段代码执行完成后,会在head标签中加入http://bbb.com这个地址的响应内容,例:
如果http://bbb.com这个地址返回的是字符串123,那么当前调用页面的结果即为
<html>
<head>
<script src=http://www.mamicode.com/"http://bbb.com" type="text/javascript">
123
</script>
</head>
<body>
</body>
</html>如果http://bbb.com这个地址返回的是test("ccc"),那么当前调用页面的结果即为
<html>
<head>
<script src=http://www.mamicode.com/"http://bbb.com" type="text/javascript">
test("ccc");
</script>
</head>
<body>
</body>
</html>看到这里应该就明白了,其实这段动态加载js的代码只是把另一个页面的内容加载到本页面了
现在这个页面运行的时候会报错,缺少test方法,因为没有定义test就调用了,我们在本地的1.html加入test方法
<html> <head> <script> function test(a){ console.log(a); } var script = document.createElement("script"); script.type = "text/javascript"; script.src = http://www.mamicode.com/"http://bbb.com";>好了,1.html就是最终的样子,执行的顺序是:
1.先初始化test方法
2.创建script标签,加载http://bbb.com的内容,将返回结果插入到head标签
3.返回结果是test("ccc") 调用了test方法,就打印出来ccc了
3.能否不使用动态创建script的方式呢,怎么感觉没用?
完全可以。
<html> <head> <script> function test(a){ console.log(a); } </script> <script src=http://www.mamicode.com/"http://bbb.com" type="text/javascript" ></script>>
这么写效果是一样的,并不是说一定要动态加载script标签才是跨域,这里是一个误区哦~那为什么要使用动态加载script标签呢?
原因有两个:
1.src动态改变,不用写死。
2.异步加载。如果src需要加载的内容返回结果较慢,动态创建script标签是异步加载的不会出现阻塞。
js的跨域已经说清楚了吧,下面我们来看下jquery的跨域
jquery跨域
大家都知道jquery 是 js写的,所以不用看源码也知道它的原理就是我们上面说的js的跨域原理我们主要说下$.ajax ,用过jquery的同学肯定都用过这个方法,封装的很好,用起来很方便jquery1.2的时候加入了jsonp这个参数类型来支持jquery的跨域,例:$.ajax({
url: "http://bbb.com",
type: "get",
data:{p1:1,p2:2},
dataType: "jsonp",
jsonp: "callback",
success: function(aaa) {
console.log(aaa);
}
});只需要在正常的ajax代码中写上红色的内容,就可以完成跨域的ajax请求了。是不是使用起来很方便O(∩_∩)O~js跨域和jquery跨域有什么优缺点?
jquery已经将所有的调用封装成对象,调用起来很方便js跨域写起来比较麻烦,尤其是传递参数的时候,需要手动拼接data ?&p1=1&p2=2但是jquery的跨域有个bug,当同时发出大量请求瞬间返回结果时,会导致接收请求的时候丢失部分回调请求(实际上已经发送成功了)例:
这种情况很常见,就是循环发送ajax请求么。非跨域请求这么写没有问题,success会被调用100次,但是当dataType : "jsonp"时,success可能只会执行70次80次,剩下的请求没有成功也没有失败,用complete也抓不到。浏览器会报错找不到callback,或无任何提示。有两个地方会引起这种问题// Clean-up function jqXHR.always(function() { // Set callback back to previous value window[ jsonpCallback ] = previous; // Call if it was a function and we have a response if ( responseContainer && jQuery.isFunction( previous ) ) { window[ jsonpCallback ]( responseContainer[ 0 ] ); } });1.callback被清除,所以有时候会报出找不到callback这个方法2.xmlHttp.readyState==4 同时发送请求的时候,浏览器的状态只有这么一个readyState当浏览器知道已经获取返回结果了,就不接收请求了这个肯定是jquery的bug,使用js跨域没有问题js&jquery跨域详解jsonp,jquery并发大量请求丢失回调bug