• 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!");
             });
  • 相关阅读:
    OpenCV---在图片上加入文字
    DosBox 报错 this program requires dosxnt.exe to be in your path
    iOS开发-UITableView单选多选/复选实现1
    LeetCode第七题,Reverse Integer
    【PostgreSQL】PostgreSQL操作-psql基本命令
    Bootstrap的js插件之弹出框(popover)
    Qt Quick 图像处理实例之美图秀秀(附源代码下载)
    【甘道夫】并行化频繁模式挖掘算法FP Growth及其在Mahout下的命令使用
    用Visual Studio高版本号打开低版本号的project,转换时出现错误:fatal error LNK1123: 转换到 COFF 期间失败: 文件无效或损坏
    如何安装ArchLinux
  • 原文地址:https://www.cnblogs.com/slowsoul/p/3059844.html
Copyright © 2020-2023  润新知