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

    1. <html>  
    2. <head>  
    3. </head>  
    4. <body>  
    5. </body>  
    6. </html

动态加载js

  1. var script = document.createElement("script");  
  2. script.type = "text/javascript";  
  3. script.src = "http://bbb.com";  
  4. var head = document.getElementsByTagName("head")[0];  
  5. head.insertBefore(script, head.firstChild); 

这段代码执行完成后,会在head标签中加入http://bbb.com这个地址的响应内容,例:

如果http://bbb.com这个地址返回的是字符串123,那么当前调用页面的结果即为

<html>
<head>
<script src="http://bbb.com" type="text/JavaScript">
123
</script>
</head>
<body>
</body>
</html>

如果http://bbb.com这个地址返回的是test("ccc"),那么当前调用页面的结果即为

<html>
<head>
<script src="http://bbb.com" type="text/javascript">
test("ccc");
</script>
</head>
<body>
</body>
</html>

看到这里应该就明白了,其实这段动态加载js的代码只是把另一个页面的内容加载到本页面了

现在这个页面运行的时候会报错,缺少test方法,因为没有定义test就调用了,我们在本地的1.html加入test方法

    1. <html>  
    2. <head>  
    3. <script>  
    4. function test(a){  
    5. console.log(a);  
    6. }  
    7.   
    8. var script = document.createElement("script");  
    9. script.type = "text/javascript";  
    10. script.src = "http://bbb.com";  
    11. var head = document.getElementsByTagName("head")[0];  
    12. head.insertBefore(script, head.firstChild);  
    13.   
    14. </script>  
    15. </head>  
    16. <body>  
    17. </body>  
    18. </html

好了,1.html就是最终的样子,执行的顺序是:

1.先初始化test方法

2.创建script标签,加载http://bbb.com的内容,将返回结果插入到head标签

3.返回结果是test("ccc") 调用了test方法,就打印出来ccc了

3.能否不使用动态创建script的方式呢,怎么感觉没用?

完全可以。

    1. <html>  
    2. <head>  
    3. <script>  
    4. function test(a){  
    5. console.log(a);  
    6. }  
    7. </script>  
    8. <script src="http://bbb.com" type="text/javascript" ></script>  
    9. </head>  
    10. <body>  
    11. </body>  
    12. </html

这么写效果是一样的,并不是说一定要动态加载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,或无任何提示。有两个地方会引起这种问题
  1. // Clean-up function  
  2. jqXHR.always(function() {  
  3.     // Set callback back to previous value  
  4.     window[ jsonpCallback ] = previous;  
  5.     // Call if it was a function and we have a response  
  6.     if ( responseContainer && jQuery.isFunction( previous ) ) {  
  7.         window[ jsonpCallback ]( responseContainer[ 0 ] );  
  8.     }  
  9. }); 

1.callback被清除,所以有时候会报出找不到callback这个方法

2.xmlHttp.readyState==4  同时发送请求的时候,浏览器的状态只有这么一个readyState当浏览器知道已经获取返回结果了,就不接收请求了
这个肯定是jquery的bug,使用js跨域没有问题

原文地址:https://www.cnblogs.com/yanan-boke/p/6856404.html