zoukankan      html  css  js  c++  java
  • ajax跨域的几种解决方法和坑

    今天在项目中要用到ajax提交数据到其它公司的接口,但ajax不允许跨域,折腾了一下午,把一些解决方法和踩到的坑记录一下。

    一、浏览器

    在chrome的快捷方式最后加上 --disable-web-security,注意前面要有个空格,且要加在引号后面。

    "C:Program Files (x86)GoogleChromeApplicationchrome.exe" --disable-web-security

    这样打开浏览器就会提示,但不影响使用。

    您使用的是不受支持的命令行标记: --disable-web-security。稳定性和安全性会有所下降

     只适用于chrome(其它浏览器没试过,不知有没有这样的参数),每台电脑的浏览器都要这样设置,不方便。

    二、提交到后台

    用ajax提交到后台(如C#的ashx),后台用WebClient之类的访问Url,返回数据给ajax的回调

    多绕了一下,如果后台有封装好访问接口的公共方法的话,倒也不算麻烦。

    三、jsonp

    jsonp也是异步请求,也有回调,所以jquery把jsonp封装到了ajax中。但其实jsonp和ajax是两码事,ajax是XMLHttpRequest,而jsonp是html的标签。在chrome开发者工具中可以看到,ajax是xhr请求,而jsonp是算到script的js请求

    jsonp是利用标签跨域的特点,生成一个新标签插入头部,来提交和返回数据。就像

    <script src="http://www.abc.com?param=1&callback=CallbackFuc"></script>

    标准使用方法,由于jsonp本质不是ajax而是<script>标签,所以只支持get。如果在参数里加上type:"POST",jquery会自动判断,同源的情况就用普通ajax进行post,不同源的情况自动转成get

    $.ajax({
        url : "http://www.abc.com?param=1",
        dataType : "jsonp",    //表示使用jsonp
        jsonp : "callback",    //传给服务器的值,为jsonpCallback服务的,两个值以&callback=jsonpCallback进行传递。不填的话默认就是callback,不想以此参数传递的话,可以填jsonp:false,这样就会生成jquery_xxxx之类的随机参数
        jsonpCallback : "jsonpCallback",    //和jsonp配合使用,服务器返回的结果是js字符串并直接执行:jsonpCallback(返回数据),jsonpCallback就是js的方法,数据就是该方法的参数
        success : function(ret){
            console.log("ok");
        },
        error : function(ret){
            console.log("err");
        }
    });

    因为最后返回的是js代码,如jsonpCallback({"key":"value"}),所以不要success和error,直接在外面定义一个方法function jsonpCallback(){}也可以。(success是jquery帮我们封装好的,便于使用)

    1、服务器端坑

    一开始以为直接datatyepe:"jsonp"就可以了,没想到一直报错,无法解析。

    本来返回的数据是json,如{"key":"value"},由于jsonp是返回直接执行的代码,所以要变成拼成jsonpCallback({"key":"value"})这样的字符串。

    好在合作公司服务端接口的同事就在旁边,改一下就可以了,碰到其它不熟的公司,人家一般不会改。

    2、循环异步jquery坑

    项目是循环异步调用,一下子发若干个请求,发现回来时,有些成功有些失败,数目不定。。。

    查了半天,总算发现一篇文章了,原来是jquery的bug。。。为避免广告,就不放原网址了,感谢原作者(原网站也没写作者,不知是不是转来的)

    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跨域没有问题

    解决方法1:加上async:false,把异步改成同步就可以了,但是会卡浏览器,循环大、返回慢的时候很不好用。

    经实践,加上异步也没用。。。

    解决方法2:改成原生js请求jsonp

    var script = document.createElement("script");
    script.type = "text/javascript";
    script.src = "http://www.abc.com?param=1&callback=jsonpCallback";  //src可以动态生成
    var head = document.getElementsByTagName("head")[0];
    head.insertBefore(script, head.firstChild);

    定义好function jsonpCallback(){},回调时就会执行(因为返回的是jsonpCallback(数据)这种形式,直接执行js代码)

    3、jquery自动转换的坑

    被这个坑害惨了,可以说一晚上都被它误导。

    前面说过,jquery把jsonp封装到ajax中,其实两者完全不同。我调试时,本身又作服务端又作客户端,实际上它是把jsonp当作ajax进行发送(chrome开发者工具中可以看到,是走xhr)

    根据同源策略,同一域不同端口也算跨域,好在机上IIS布了两个端口用于两个项目的调试,把服务端布到另一个项目上,这样调试时jquery就会自动识别使用jsonp(开发者工具看到走的是js)

    四、改进jquery的jsonp

    虽然原生的是可以解决问题,但平时jquery用习惯了,尝试着改进一下。由于主要是因为瞬间大量并发请求造成jquery的Bug,那么就在这里面做文章

    1、延时执行

    前端

    var interVal=0;
    for(var i=0;i<1000;i++){
        interVal += 1000;  //这个值根据数据返回速度进行设置,快的话200也可以
        setTimeout(function(){
            interVal += 1000;
            $.ajax({
                //省略
            });
        },interVal)
    }

    后端

    Thread.Sleep(500);
    Response.Write("jsonpCallback({"key":"value"})");

    用Thread.Sleep来模拟网络阻塞

    如果网络状况好,返回数据快,interVal可以设成每次递增200。这个值要大于数据请求所用的时间,不然还是会并发导致jquery的Bug

    这个方法可以凑合着用,特别是对一些后台的自动任务,间隔设大一些无所谓,让它慢慢跑。偶尔出一些错也不要紧,下次再循环时还会去请求。

    2、响应式

    使用$.Deferred()配合$.when()、$.then()、$.done()、$.fail(),一个完成后再调用下一个。

    比较高级的用法,之前有在项目中试用过,好像还是会一口气把循环里的ajax请求全发出去,而不是一个个排队发。这里就不尝试了

    3、递归

    循环ajax时非常好用的手段,也是踩了无数坑研究出来的,成就感非常强。

    先执行第一个ajax,在success和error里,都要执行递归,然后把计数器++,根据计数器==循环总数进行判断是否完成循环。

    递归的好处就是界面上可以友好的显示正在执行第几个,每个的结果是什么,而且是按顺序执行的(不像发一堆ajax出去,回来时零零散散的),还可以随时中断。

    缺点就是多重ajax时,每一个都要判断error并递归,如果漏了,在那个环节出错的话,就不会继续下去。

    这里也懒的再尝试了

  • 相关阅读:
    adb命令之adb install
    GNU make and Makefile
    Makefile经典教程(掌握这些足够)
    Android.mk简介
    PhoneFactory.getDefaultPhone must be called from Looper thread
    Android源码目录结构
    软件部通用技术类网站名录
    β测试
    α测试
    白盒测试
  • 原文地址:https://www.cnblogs.com/liuyouying/p/5051936.html
Copyright © 2011-2022 走看看