• Ajax——《JavaScript高级程序设计》笔记


    Ajax通信与数据格式无关,从服务器获取的数据不一定是XML数据。

     Ajax的核心:XMLHttpRequest对象(简称XHR)

           在XHR对象之前,Ajax通信通常使用hack手段,如使用隐藏的或内嵌的框架。

           XHR对象为向服务器发送信息和解析服务器响应提供了流畅的接口。

    1.XMLHttpRequest对象

           IE5是第一款引进XHR对象的浏览器,通过MSXML库中的ActiveX对象实现(有3个版本)。

      兼容所有浏览器,创建XHR对象:

    创建标准XHR对象
    function createXHR(){
        if (typeof XMLHttpRequest != "undefined"){
            return new XMLHttpRequest();
        } else if (typeof ActiveXObject != "undefined"){
            if (typeof arguments.callee.activeXString != "string"){
                var versions = ["MSXML2.XMLHttp.6.0", "MSXML2.XMLHttp.3.0",
                                "MSXML2.XMLHttp"],
                    i, len;
        
                for (i=0,len=versions.length; i < len; i++){
                    try {
                        new ActiveXObject(versions[i]);
                        arguments.callee.activeXString = versions[i];
                        break;
                    } catch (ex){
                        //skip
                    }
                }
            }
        
            return new ActiveXObject(arguments.callee.activeXString);
        } else {
            throw new Error("No XHR object available.");
        }
    }

       之后就能在所有浏览器创建XHR对象:var xhr = createrXHR();

    2.原生XHR对象 (支持的浏览器: IE7+、FF、Chrome、Opera、Safari)

           通过XMLHttpRequest构建函数,创建XHR对象:

    var xhr = new XMLHttpRequest();

    3.XHR用法

    3-1.open()

           open() 3个参数: 发送的类型、请求的URL、表是否异步的布尔值

    xhr.open("get","example.php", false);

           ①URl为相对于执行代码的当前页,或绝对地址;

           ②false为同步,JavaScript代码会在服务器响应后再继续执行;

           ③调用open()只是启动一个请求以备发送,还没真正发送;

           ④只能在同个域中使用相同端口和协议的URL发送请求。

    3-2.send()

           send() 1个参数: 请求主体发送的数据,不需要通过请求主体发送数据则传入null。

           调用send()后,请求被分派到服务器。

    xhr.open("get","example.php", false) ;
    xhr.send(null);

    3-3. 收到响应后,响应数据会自动填充XHR对象的属性:

           responseText:作为响应的主体被返回的文本;

           responseXML:若响应的内容类型”text/xml”或”application/xml”,此属性保存响应数据XML DOM文档

           status:响应的HTTP状态;

           statusText:HTTP状态的说明。

    ☆:无论什么内容类型,响应主体的内容都会保存在responseText属性中。对于非XML数据,responseXML属性值为null。
    3-4.status属性确认响应是否成功返回

    HTTP状态代:

           200:响应有效,responseText属性已就绪,内容类型正确下的responseXML也可访问。

           304:响应有效,只是请求的资源并为修改,可直接使用浏览器中缓存的版本。

           正确检查上述2种状态代码:

    status判断

    status判断
     if ((xhr.status >= 200 && xhr.status <=300) || xhr.status == 304) {
         alert(xhr.responseText);
    } else {
         alert("Request was unsuccessful:" + xhr.status);
    };

    3-5.readystate属性

           该属性存储 请求/响应过程的 当前活动状态。

                  0 : 未初始化,未调用open();
                  1 : 启动,调用了open();
                  2 : 发送,调用了send(),未接受响应;
                  3 : 接受,已接受部分响应;
                  4 : 完成,已接受全部响应,且可在客户端使用。

    3-6.readystatechange事件

           该事件,在readystate属性值改变时触发。

    readystatechange事件句柄
    var xhr = createXHR();
    xhr.onreadystatechange = function(event){
        if (xhr.readyState == 4){
            if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304){
                alert(xhr.responseText);
            } else {
                alert("Request was unsuccessful: " + xhr.status);
            }
        }
    };
    xhr.open("get", "example.txt", true);
    xhr.send(null);

           ①必须在调用open()之前知道readystatechange事件的事件处理程序,确保兼容。

           ②该事件处理程序中没有传递event对象,必须通过XHR对象本地来确定下一步怎么做;

           ③使用xhr对象而不使用this对象,是因为onreadystatechange事件处理程序的作用域问题。使用this对象在一些浏览器会导致函数执行失败或发生错误。

    3-7.abort()

           调用此方法可取消异步请求:xhr.abort();

           调用后,xhr对象停止触发事件,不允许访问如何与响应相关的属性;

           终止请求后,应对XHR对象进行解引用操作,不建议重用XHR对象。

    4、HTTP头部信息

           发送请求时的头部信息:

                  Accept:浏览器能够处理的内容类型

                  Accept-Charset:浏览器能够显示的字符集

                  Accept-Encoding:浏览器能够处理的压缩编码

                  Axxept-Language:浏览器当前设置的语言

                  Connection:浏览器与服务器之间连接的类型

                  Cookie:当前页面设置的如何Cookie

                  Host:发送请求耳洞页面所在域

                  Referer:发出请求的页面的URI

                  User-Agent:浏览器的用户代理字符串

           setRequestHeader()

                  设置自定义头部信息。

                  2个参数:头部字段名称、头部信息值。

                  需在open()方法之后调用send()之前调用setRequestHeader(),才能成功发送请求头部信息。

    自定义HTTP头部信息
    var xhr = createXHR();       
    xhr.onreadystatechange = function(){
        if (xhr.readyState == 4){
            if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304){
                alert(xhr.responseText);
            } else {
                alert("Request was unsuccessful: " + xhr.status);
            }
        }
    };
    xhr.open("get", "example.php", true);
    xhr.setRequestHeader("MyHeader", "MyValue");
    xhr.send(null);

            getRequestHeader()

                  获取指定的相应头部信息

    xhr.getRequestHeader(“MyHeader”);

           getAllRequestHeader()

                  获取一个包含所有头部信息的长字符串

    xhr.getAllRequestHeader();

    5、GET请求

      对于XHR对象,位于opne()的URL末尾的查询字符串 需经过编码,使用encodeURIComponent()编码。

      名-值对需用和号(&)分隔。

      自定义函数,添加URL查询字符串参数:

    辅助函数:添加查询字符串参数
    function addURLParam(url,name,value){
        url += (url.indexOf('?') == -1?'?':'&');
        url += encodeURIComponent(name) + '=' + encodeURIComponent(value);
        return url;
    }

    6、POST请求

      长用于想服务器发送要保存的数据。

      由于XHR其初的设计是为了处理XML,故在send(0中可传入XHR DOM文档。

    6-1.服务端读取POST数据

      ①默认情况下,服务器对POST请求和提交Web表单不会一视同仁,故服务端需要程序来读取发送的原始数据,并解析出有用部分。

      ②XHR模拟表单提交:

        1.将Content-Type头部信息设置为application/x-www-form-urlencoded (即表单提交时的内容问题);

        2.以适当格式创建一个字符串。(通过serialize()函数创建该字符串,序列化表单数据)

    XHR模拟表单提交
    function submitData(){
        var xhr = createXHR();        
        xhr.onreadystatechange = function(event){
            if (xhr.readyState == 4){
                if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304){
                    alert(xhr.responseText);
                } else {
                    alert("Request was unsuccessful: " + xhr.status);
                }
            }
        };
    
        
    
        xhr.open("post", "postexample.php", true);
        xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
        var form = document.getElementById("user-info");            
        xhr.send(serialize(form));
    }

     7、CORS 跨源资源共享(IE8+、FF、Chrome....)

       跨域安全策略限制了Ajax的异步通信,CORS则是定义了跨域时,客户端和服务器的沟通。

      CORS思想:使用自定义HTTP头部让浏览器与服务器进行沟通,从而决定请求/响应的成功与否。

    7-1.给一个请求附加Origin头部,包含请求页面的源信息(协议、域名 和 端口)

    Origin: http://www.domain.com

      服务器根据Origin判断是否接收请求,接收则在Access-Control-Allow-Origin头部会发相同信息。

        (若是公共资源,可以回发"*")

    Access-Control-Allow-Origin: http://www.domain.com

      若无此头部或头部信息不匹配,浏览器将驳回请求。

    ☆请求和响应不会包含cookie信息。

     7-2.IE8+对CORS的实现

      IE8引入的XDR(XDomainRequest)类型,类型XHR,可实现安全可靠的跨域通信。

    7-2-1.XDR与XHR的不同之处:

      ①cookie不会随请求发送,也不会随响应返回;

      ②只能设置请求头部信息中的Content-Type字段;

      ③不能访问响应头部信息;

      ④只支持GET和POST请求

    XDR缓解了CSRF(跨站请求伪造)和XSS(跨站点脚本)问题

    被请求的资源可判断用户代理、来源页面等如何数据 来决定是否设置Access-Control-Allow-Origin头部

     7-2-2. XDR使用方法类似XHR,创建一个XDomainRequest实例,调用open(),再调用send()。

      XDR只能执行异步请求,所以open()方法只有两个参数,请求的类型和URL。

      在收到响应后,只能访问响应的原始文本,无法确定响应的状态代码。

      只要响应有效就会触发load事件,响应的数据会保存在responseText属性中。

      如果失败(如,响应中缺少Access-Control-Allow-Origin头部)就会触发error事件,但该事件无有用信息,需要自定义一个onerror事件句柄。

    obload事件-onerror事件
    var xdr = new XDomainRequest();
    xdr.onload = function(){
        alert(xdr.responseText);
    };
    xdr.onerror = function(){
        alert("Error!");
    };
    
    xdr.open("get", "http://www.somewhere-else.com/xdr.php");
    xdr.send(null);  

      在请求返回前调用abort()可终止请求。

    7-2-3.XDR也支持timeout属性及ontiomout事件处理程序,在运行超过timeout设定的秒数后,调用ontimeout事件句柄。

      为支持POST请求,XDR提供了contentType属性,用于表示发送数据的格式。

        contentType属性是XDR对象影响头部信息的唯一方式。

    xdr.contentType = "application/x-www-form-urlencoded";

    7-3其他浏览器对CORS的实现

      FF等浏览器都通过XMLHttpRequest对象实现了对CORS的原生支持。要请求另一个域中的资源时,使用标准XHR对象并在open()中传入绝对URL即可。

    标准XHR的跨域
    var xhr = createXHR();        
    xhr.onreadystatechange = function(){
        if (xhr.readyState == 4){
            if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304){
                alert(xhr.responseText);
            } else {
                alert("Request was unsuccessful: " + xhr.status);
            }
        }
    };
    xhr.open("get", "http://www.abc.com/page/", true);
    xhr.send(null);

       与IE不同,通过跨域XHR对象可以访问status属性和statusText属性,也可同步请求。

    7-3-1.跨域XHR的限制:

      ①不能使用setRequestHeader()设置自定义头部;

      ②不能发送和接收cookie;

      ③调用getAllResponseHeader()方法总会返回空字符串。

     7-3-2.无论同源请求还是跨域请求都是使用相同的接口,故对于本地资源,最好用相对URL,对远程资源再用绝对URL。

      这样能消除歧义,避免出现限制访问头部或本地cookie信息等问题。

     7-4、跨浏览器的CORS(IE8+、FF等)

       检测XHR是否支持CORS的方法:检查是否存在withCredentials属性,在结合检测XDomainRequest对象是否存在。

    CORS跨域兼容
    function createCORSRequest(method, url){
        var xhr = new XMLHttpRequest();
        if ("withCredentials" in xhr){
            xhr.open(method, url, true);
        } else if (typeof XDomainRequest != "undefined"){
            xhr = new XDomainRequest();
            xhr.open(method, url);
        } else {
            xhr = null;
        }
        return xhr;
    }
    
    var request = createCORSRequest("get", "http://www.somewhere-else.com/xdr.php");
    if (request){
        request.onload = function(){
            //do something with request.responseText
        };
        request.send();
    }

      上述createCORSRequest()函数返回的对象的属性(XHR和XDR的共同属性):

      ①abort():停止正在进行的请求;

      ②onerror:用于替代onreadystatechange检测错误;

      ③onload:用于代替onreadystatechange检测成功;

      ④responseText:用于取得响应内容;

      ⑤send():用于发送请求。

    8、其他跨域技术

      在CORS出现前,常利用DOM中能够执行跨域请求的功能,在不依赖XHR对象时,也能发送某种请求。

      与COSR不同的是,不用修改服务器代码。

    8-1.图像Ping

      使用<img>标签,由于可以从任何网页加载图像,故常是在线广告跟踪浏览量的只要方式。

      可动态创建图像,使用它们的onload和onerror事件句柄,确定是否接受到了响应。

    var img = new Image();
    img.onload = img.onerror = function(){
        alert("Done!");
    };
    img.src = "http://www.example.com/test?name=Nicholas"; 

      图像Ping是与服务器进行简单、单向的跨域通信的一种方式。请求的数据通过查询字符串形式发送,响应可以是任何内容,通常是像素图或204响应。虽然通过图像Ping,浏览器得不到任何具体数据,但通过侦听load和error事件,能找到响应收到的时间。

      图像Ping常用于跟踪用户点击页面 或动态广告曝光次数。

      缺点:①只能发送GET请求;②无法访问服务器响应文本。

    8-2.JSONP

      JSONP(JSON width Padding)填充式JSON或参数式JSON,类似JSON,是包含在函数调用中的JSON:

    callback( {"name" : "value"} );

    8-2-1.JSONP有两个部分:回调函数 和 数据

      回调函数:当响应到来时应该在页面中调用的函数。回调函数的名称在请求中指定。

      数据:传入回调函数的JSON数据。

    8-2-2.JSONP通过动态<script>元素,为其src属性指定一个跨域的URL。类似<img>元素,即都能不受限制地跨域加载资源。

      JSONP为有效的JavaScript代码,在请求完成即JSONP响应 加载到页面后就会立即执行。

    View Code
    function handleResponse(response){
        alert("You're at IP address " + response.ip + ", which is in " + response.city + ", " + response.region_name);
    }
    
    var script = document.createElement("script");
    script.src = "http://freegeoip.net/json/?callback=handleResponse";
    document.body.insertBefore(script, document.body.firstChild);

      headleResponse()为回调函数,将在响应到来后执行。

    8-2-3.JSONP之所以流行,是因为 :

        ①能够直接访问响应文本;

        ②支持浏览器与服务器之间的双向通信。

      不足:

        ①JSONP从其他域加载代码执行,因此该域必须安全可靠;

        ②很难确保JSONP请求是否失败。

    8-3Comet ”服务器推送" 【不兼容IE】

       Ajax从页面想服务器请求数据,Comet则是服务器向页面推送数据,Comet能近乎实时地向页面推送信息。

     8-3-1.实现Comet的2种方式:长轮询 和 流

      ①长轮询:与短轮询相反,页面发送一个请求,服务器一直保持连接打开,直到有数据可发送时就向页面发送数据。接收完数据后浏览器关闭连接,随机又发送一个新请求,在页面打开期间如此循环...

      【短轮询是服务器立即发送数据,即使数据无效,长轮询是等待发送响应。】

      轮询的优点是,所有浏览器都支持。通过XHR对象和setTimeout()实现。

      ②HTTP流:它在网页的整个生命周期内只使用一个HTTP连接。浏览器发送一个请求,服务器保持连接打开,再周期性向浏览器发送数据.

    PHP例子
    <?php
      $i = 0;
      while (true) {
        //输出一些数据,然后刷新输出缓存
        echo "Number is $1";
        flush();
    
        //等几秒
        sleep(10);
    
        $++;
      }
    ...

      实现HTTP流的关键:所有服务器端语言都支持打印到输出缓存然后刷新的功能。(将输出缓存中的内容一次性全部发送给客户端)

    使用XHR实现HTTP流的典型例子
    var xhr = new XMLHttpRequest(),
        received = 0;
        
    xhr.open("get", url, true);
    xhr.onreadystatechange = function(){
        var result;
        
        if (xhr.readyState == 3){
        
            //get only the new data and adjust counter
            result = xhr.responseText.substring(received);
            received += result.length;
            
            //call the progress callback
            progress(result);
            
        } else if (xhr.readyState == 4){
            finished(xhr.responseText);
        }
    };
    xhr.send(null);
    return xhr;
    }
    
    var client = createStreamingClient("streaming.php", function(data){
                alert("Received: " + data);
             }, function(data){
                alert("Done!");
             });
  • 相关阅读:
    leetcode 268. Missing Number
    DBSCAN
    python二维数组初始化
    leetcode 661. Image Smoother
    leetcode 599. Minimum Index Sum of Two Lists
    Python中的sort() key含义
    leetcode 447. Number of Boomerangs
    leetcode 697. Degree of an Array
    滴滴快车奖励政策,高峰奖励,翻倍奖励,按成交率,指派单数分级(1月3日)
    北京Uber优步司机奖励政策(1月2日)
  • 原文地址:https://www.cnblogs.com/slowsoul/p/3059844.html
Copyright © 2020-2023  润新知