zoukankan      html  css  js  c++  java
  • 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跨域没有问题

  • 相关阅读:
    CSS 两个行内块元素,宽度相加刚好等于父盒子容器的元素,但第二个元素掉在第二行解决办法
    js 自定义获得类class和获得id
    学习笔记:BSGS(拔山盖世?)算法
    解题报告: luogu P1040
    解题报告:SP18155 ABSP1
    解题报告:luogu P1099
    Thussat 游记
    解题报告:luogu P2220
    学习笔记:卢卡斯定理(并没有学会)
    从线性筛到欧拉函数,你十有八九能懂吧!
  • 原文地址:https://www.cnblogs.com/yanan-boke/p/6856404.html
Copyright © 2011-2022 走看看