xmlhttprequest_xmlhttprequest对象 - CSDN
xmlhttprequest 订阅
XMLHTTP是一组API函数集,可被JavaScript、JScript、VBScript以及其它web浏览器内嵌的脚本语言调用,通过HTTP在浏览器和web服务器之间收发XML或其它数据。XMLHTTP最大的好处在于可以动态地更新网页,它无需重新从服务器读取整个网页,也不需要安装额外的插件。该技术被许多网站使用,以实现快速响应的动态网页应用。例如:Google的Gmail服务、Google Suggest动态查找界面以及Google Map地理信息服务。 展开全文
XMLHTTP是一组API函数集,可被JavaScript、JScript、VBScript以及其它web浏览器内嵌的脚本语言调用,通过HTTP在浏览器和web服务器之间收发XML或其它数据。XMLHTTP最大的好处在于可以动态地更新网页,它无需重新从服务器读取整个网页,也不需要安装额外的插件。该技术被许多网站使用,以实现快速响应的动态网页应用。例如:Google的Gmail服务、Google Suggest动态查找界面以及Google Map地理信息服务。
信息
外文名
XMLHTTP
标准化
对象还没有标准化
特    点
提供了对 HTTP 协议的完全的访问
中文名
XmlHttpRequest
优    点
得到了所有现代浏览器较好的支持
XMLHTTPRequest简介
XMLHTTP是一组API函数集,可被JavaScript、JScript、VBScript以及其它web浏览器内嵌的脚本语言调用,通过HTTP在浏览器和web服务器之间收发XML或其它数据。XMLHTTP最大的好处在于可以动态地更新网页,它无需重新从服务器读取整个网页,也不需要安装额外的插件。该技术被许多网站使用,以实现快速响应的动态网页应用。例如:Google的Gmail服务、Google Suggest动态查找界面以及Google Map地理信息服务。XMLHTTP是AJAX网页开发技术的重要组成部分。除XML之外,XMLHTTP还能用于获取其它格式的数据,如JSON或者甚至纯文本。 [1] 
收起全文
精华内容
参与话题
  • 原文出处:https://www.jianshu.com/p/918c63045bc3 (简书小军617) 延伸阅读:XMLHttpRequest使用详解 (含:跨域资源共享(CORS))

    原文出处:https://www.jianshu.com/p/918c63045bc3 (简书 小军617)
    延伸阅读:XMLHttpRequest使用详解  (含:跨域资源共享(CORS))

    展开全文
  • AJAX——核心XMLHttpRequest对象

    万次阅读 多人点赞 2013-12-15 11:15:38
    AJAX大家已经都知道了,...而,XMLHttpRequest对象则是其中的重重之中。这篇博客重点总结一下这个对象的使用。当然还是按照经典的五步法来学习,以后在实践中有更多更好的想法,会拿出来分享的!  首先,需要先了解

              AJAX大家已经都知道了,是为了实现异步通讯,提高用户体验度,而将很多旧知识(XML,DOM,JavaScript,HTML,Jquery,Css……)重新融合的一个新的知识框架。而,XMLHttpRequest对象则是其中的重重之中。这篇博客重点总结一下这个对象的使用。当然还是按照经典的五步法来学习,以后在实践中有更多更好的想法,会拿出来分享的!


               首先,需要先了解这个对象的属性和方法:


    属性

    说明

    readyState

    表示XMLHttpRequest对象的状态:0:未初始化。对象已创建,未调用open

    1open方法成功调用,但Sendf方法未调用;

    2send方法已经调用,尚未开始接受数据;

    3:正在接受数据。Http响应头信息已经接受,但尚未接收完成;

    4:完成,即响应数据接受完成。

    Onreadystatechange

    请求状态改变的事件触发器(readyState变化时会调用这个属性上注册的javascript函数)。

    responseText

    服务器响应的文本内容

    responseXML

    服务器响应的XML内容对应的DOM对象

    Status

    服务器返回的http状态码。200表示“成功”,404表示“未找到”,500表示“服务器内部错误”等。

    statusText

    服务器返回状态的文本信息。



    方法

    说明

    Open(string method,string url,boolean asynch,

    String username,string password)

    指定和服务器端交互的HTTP方法,URL地址,即其他请求信息;

    Method:表示http请求方法,一般使用"GET","POST".

    url:表示请求的服务器的地址;

    asynch:表示是否采用异步方法,true为异步,false为同步;

    后边两个可以不指定,usernamepassword分别表示用户名和密码,提供http认证机制需要的用户名和密码。

    Send(content)

    向服务器发出请求,如果采用异步方式,该方法会立即返回。

    content可以指定为null表示不发送数据,其内容可以是DOM对象,输入流或字符串。

    SetRequestHeader(String header,String Value)

    设置HTTP请求中的指定头部header的值为value.

    此方法需在open方法以后调用,一般在post方式中使用。

    getAllResponseHeaders()

    返回包含Http的所有响应头信息,其中相应头包括Content-length,date,uri等内容。

    返回值是一个字符串,包含所有头信息,其中每个键名和键值用冒号分开,每一组键之间用CRLF(回车加换行符)来分隔!

    getResponseHeader(String header)

    返回HTTP响应头中指定的键名header对应的值

    Abort()

    停止当前http请求。对应的XMLHttpRequest对象会复位到未初始化的状态。



              对这个对象有了静态了了解,知道它长的什么样子,有什么功能了,下边该我们使用它了,当然这里我也用五步法写出代码来:

    第一步:创建XMLHttpRuquest对象:

     var xmlhttprequest;
        if(window.XMLHttpRequest){
            xmlhttprequest=new XMLHttpRequest();
            if(xmlhttprequest.overrideMimeType){
                xmlhttprequest.overrideMimeType("text/xml");
            }
        }else if(window.ActiveXObject){
            var activeName=["MSXML2.XMLHTTP","Microsoft.XMLHTTP"];
            for(var i=0;i<activeName.length;i++){
                try{
                    xmlhttprequest=new ActiveXObject(activeName[i]);
                    break;
                }catch(e){
                           
                }
            }
        }
        
        if(xmlhttprequest==undefined || xmlhttprequest==null){
            alert("XMLHttpRequest对象创建失败!!");
        }else{
            this.xmlhttp=xmlhttprequest;
        }
    


        第二步:注册回调方法


    xmlhttp.onreadystatechange=callback;
    

        第三步:设置和服务器交互的相应参数

     xmlhttp.open("GET","ajax?name=" +userName,true);
    

        第四步:设置向服务器端发送的数据,启动和服务器端的交互


      xmlhttp.send(null);

        第五步:判断和服务器端的交互是否完成,还要判断服务器端是否返回正确的数据


    //根基实际条件写callback的功能代码
    function callback(){
    	 if(xmlhttp.readState==4){
    		 //表示服务器的相应代码是200;正确返回了数据 
    		if(xmlhttp.status==200){ 
    			//纯文本数据的接受方法 
    			var message=xmlhttp.responseText; 
    			//使用的前提是,服务器端需要设置content-type为text/xml 
    			//var domXml=xmlhttp.responseXML; 
    			//其它代码
    		 } 
    	}
     }
    

             通过这五步XMLHttpRequest基本上就创建好,可以正常使用了,但是这是需要非常多的代码的,总不能每次创建都写这么多吧?当然不是了,我们学习了面向对象,我们将其必要相同的部分都抽象出来,使之成为一个独立类,别的直接调用即可,在网上看了一个,感觉写的挺好:


    //类的构建定义,主要职责就是新建XMLHttpRequest对象
    var MyXMLHttpRequest=function(){
        var xmlhttprequest;
        if(window.XMLHttpRequest){
            xmlhttprequest=new XMLHttpRequest();
            if(xmlhttprequest.overrideMimeType){
                xmlhttprequest.overrideMimeType("text/xml");
            }
        }else if(window.ActiveXObject){
            var activeName=["MSXML2.XMLHTTP","Microsoft.XMLHTTP"];
            for(var i=0;i<activeName.length;i++){
                try{
                    xmlhttprequest=new ActiveXObject(activeName[i]);
                    break;
                }catch(e){
                           
                }
            }
        }
        
        if(xmlhttprequest == undefined || xmlhttprequest == null){
            alert("XMLHttpRequest对象创建失败!!");
        }else{
            this.xmlhttp=xmlhttprequest;
        }
        
        //用户发送请求的方法
        MyXMLHttpRequest.prototype.send=function(method,url,data,callback,failback){
            if(this.xmlhttp!=undefined && this.xmlhttp!=null){
                method=method.toUpperCase();
                if(method!="GET" && method!="POST"){
                    alert("HTTP的请求方法必须为GET或POST!!!");
                    return;
                }
                if(url==null || url==undefined){
                    alert("HTTP的请求地址必须设置!");
                    return ;
                }
                var tempxmlhttp=this.xmlhttp;
                this.xmlhttp.onreadystatechange=function(){
                    if(tempxmlhttp.readyState==4){
                        if(temxmlhttp.status==200){
                            var responseText=temxmlhttp.responseText;
                            var responseXML=temxmlhttp.reponseXML;
                            if(callback==undefined || callback==null){
                                alert("没有设置处理数据正确返回的方法");
                                alert("返回的数据:" + responseText);
                            }else{
                                callback(responseText,responseXML);
                            }
                        }else{
                            if(failback==undefined ||failback==null){
                                alert("没有设置处理数据返回失败的处理方法!");
                                alert("HTTP的响应码:" + tempxmlhttp.status + ",响应码的文本信息:" + tempxmlhttp.statusText);
                            }else{
                                failback(tempxmlhttp.status,tempxmlhttp.statusText);
                            }
                        }
                    }
                }
                
                //解决缓存的转换
                if(url.indexOf("?")>=0){
                    url=url + "&t=" + (new Date()).valueOf();
                }else{
                    url=url+"?+="+(new Date()).valueOf();
                }
                
                //解决跨域的问题
                if(url.indexOf("http://")>=0){
                    url.replace("?","&");
                    url="Proxy?url=" +url;
                }
                this.xmlhttp.open(method,url,true);
                
                //如果是POST方式,需要设置请求头
                if(method=="POST"){
                    this.xmlhttp.setRequestHeader("Content-type","application/x-www-four-urlencoded");
                }
                this.xmlhttp.send(data);
        }else{
            alert("XMLHttpRequest对象创建失败,无法发送数据!");
        }
        MyXMLHttpRequest.prototype.abort=function(){
            this.xmlhttp.abort();
        }
      }
    }
    

              当然这些都需要我们在实践中不断的摸索,使用,再总结属于自己的一套常用类,方法等。当然XMLHttpRequest还有“浏览器缓存问题”,“中文乱码问题”,“跨域访问问题”等等,因为都没有遇到过这些东西,所以这里先了解一下,以后遇到再认真研究!



    展开全文
  • XMLHttpRequest 详解

    万次阅读 多人点赞 2018-06-01 15:40:42
    XMLHttpRequest的发展历程XMLHttpRequest一开始只是微软浏览器提供的一个接口,后来各大浏览器纷纷效仿也提供了这个接口,再后来W3C对它进行了标准化,提出了XMLHttpRequest标准。XMLHttpRequest标准又分为Level 1和...

    XMLHttpRequest的发展历程

    XMLHttpRequest一开始只是微软浏览器提供的一个接口,后来各大浏览器纷纷效仿也提供了这个接口,再后来W3C对它进行了标准化,提出了XMLHttpRequest标准XMLHttpRequest标准又分为Level 1Level 2
    XMLHttpRequest Level 1主要存在以下缺点:

    • 受同源策略的限制,不能发送跨域请求;

    • 不能发送二进制文件(如图片、视频、音频等),只能发送纯文本数据;

    • 在发送和获取数据的过程中,无法实时获取进度信息,只能判断是否完成;

    那么Level 2Level 1 进行了改进,XMLHttpRequest Level 2中新增了以下功能:

    • 可以发送跨域请求,在服务端允许的情况下;

    • 支持发送和接收二进制数据;

    • 新增formData对象,支持发送表单数据;

    • 发送和获取数据时,可以获取进度信息;

    • 可以设置请求的超时时间;

    当然更详细的对比介绍,可以参考阮老师的这篇文章,文章中对新增的功能都有具体代码示例。

    XMLHttpRequest兼容性

    关于xhr的浏览器兼容性,大家可以直接查看“Can I use”这个网站提供的结果XMLHttpRequest兼容性,下面提供一个截图。

    clipboard.png

    从图中可以看到:

    • IE8/IE9、Opera Mini 完全不支持xhr对象

    • IE10/IE11部分支持,不支持 xhr.responseTypejson

    • 部分浏览器不支持设置请求超时,即无法使用xhr.timeout

    • 部分浏览器不支持xhr.responseTypeblob

    细说XMLHttpRequest如何使用

    先来看一段使用XMLHttpRequest发送Ajax请求的简单示例代码。

    function sendAjax() {
      //构造表单数据
      var formData = new FormData();
      formData.append('username', 'johndoe');
      formData.append('id', 123456);
      //创建xhr对象 
      var xhr = new XMLHttpRequest();
      //设置xhr请求的超时时间
      xhr.timeout = 3000;
      //设置响应返回的数据格式
      xhr.responseType = "text";
      //创建一个 post 请求,采用异步
      xhr.open('POST', '/server', true);
      //注册相关事件回调处理函数
      xhr.onload = function(e) { 
        if(this.status == 200||this.status == 304){
            alert(this.responseText);
        }
      };
      xhr.ontimeout = function(e) { ... };
      xhr.onerror = function(e) { ... };
      xhr.upload.onprogress = function(e) { ... };
      
      //发送数据
      xhr.send(formData);
    }
    

    上面是一个使用xhr发送表单数据的示例,整个流程可以参考注释。


    接下来我将站在使用者的角度,以问题的形式介绍xhr的基本使用。
    我对每一个问题涉及到的知识点都会进行比较细致地介绍,有些知识点可能是你平时忽略关注的。

    如何设置request header

    在发送Ajax请求(实质是一个HTTP请求)时,我们可能需要设置一些请求头部信息,比如content-typeconnectioncookieaccept-xxx等。xhr提供了setRequestHeader来允许我们修改请求 header。

    void setRequestHeader(DOMString header, DOMString value);

    注意点

    • 方法的第一个参数 header 大小写不敏感,即可以写成content-type,也可以写成Content-Type,甚至写成content-Type;

    • Content-Type的默认值与具体发送的数据类型有关,请参考本文【可以发送什么类型的数据】一节;

    • setRequestHeader必须在open()方法之后,send()方法之前调用,否则会抛错;

    • setRequestHeader可以调用多次,最终的值不会采用覆盖override的方式,而是采用追加append的方式。下面是一个示例代码:

    var client = new XMLHttpRequest();
    client.open('GET', 'demo.cgi');
    client.setRequestHeader('X-Test', 'one');
    client.setRequestHeader('X-Test', 'two');
    // 最终request header中"X-Test"为: one, two
    client.send();

    如何获取response header

    xhr提供了2个用来获取响应头部的方法:getAllResponseHeadersgetResponseHeader。前者是获取 response 中的所有header 字段,后者只是获取某个指定 header 字段的值。另外,getResponseHeader(header)header参数不区分大小写。

    DOMString getAllResponseHeaders();
    DOMString getResponseHeader(DOMString header);

    这2个方法看起来简单,但却处处是坑儿。

    你是否遇到过下面的坑儿?——反正我是遇到了。。。

    1. 使用getAllResponseHeaders()看到的所有response header与实际在控制台 Network 中看到的 response header不一样

    2. 使用getResponseHeader()获取某个 header 的值时,浏览器抛错Refused to get unsafe header "XXX"

    经过一番寻找最终在 Stack Overflow找到了答案

    "simple response header"包括的 header 字段有:Cache-Control,Content-Language,Content-Type,Expires,Last-Modified,Pragma;
    "Access-Control-Expose-Headers":首先得注意是"Access-Control-Expose-Headers"进行跨域请求时响应头部中的一个字段,对于同域请求,响应头部是没有这个字段的。这个字段中列举的 header 字段就是服务器允许暴露给客户端访问的字段。

    所以getAllResponseHeaders()只能拿到限制以外(即被视为safe)的header字段,而不是全部字段;而调用getResponseHeader(header)方法时,header参数必须是限制以外的header字段,否则调用就会报Refused to get unsafe header的错误。

    如何指定xhr.response的数据类型

    有些时候我们希望xhr.response返回的就是我们想要的数据类型。比如:响应返回的数据是纯JSON字符串,但我们期望最终通过xhr.response拿到的直接就是一个 js 对象,我们该怎么实现呢?
    有2种方法可以实现,一个是level 1就提供的overrideMimeType()方法,另一个是level 2才提供的xhr.responseType属性。

    xhr.overrideMimeType()

    overrideMimeTypexhr level 1就有的方法,所以浏览器兼容性良好。这个方法的作用就是用来重写responsecontent-type,这样做有什么意义呢?比如:server 端给客户端返回了一份document或者是 xml文档,我们希望最终通过xhr.response拿到的就是一个DOM对象,那么就可以用xhr.overrideMimeType('text/xml; charset = utf-8')来实现。

    再举一个使用场景,我们都知道xhr level 1不支持直接传输blob二进制数据,那如果真要传输 blob 该怎么办呢?当时就是利用overrideMimeType方法来解决这个问题的。

    下面是一个获取图片文件的代码示例:

    var xhr = new XMLHttpRequest();
    //向 server 端获取一张图片
    xhr.open('GET', '/path/to/image.png', true);
    
    // 这行是关键!
    //将响应数据按照纯文本格式来解析,字符集替换为用户自己定义的字符集
    xhr.overrideMimeType('text/plain; charset=x-user-defined');
    
    xhr.onreadystatechange = function(e) {
      if (this.readyState == 4 && this.status == 200) {
        //通过 responseText 来获取图片文件对应的二进制字符串
        var binStr = this.responseText;
        //然后自己再想方法将逐个字节还原为二进制数据
        for (var i = 0, len = binStr.length; i < len; ++i) {
          var c = binStr.charCodeAt(i);
          //String.fromCharCode(c & 0xff);
          var byte = c & 0xff; 
        }
      }
    };
    
    xhr.send();

    代码示例中xhr请求的是一张图片,通过将 response 的 content-type 改为'text/plain; charset=x-user-defined',使得 xhr 以纯文本格式来解析接收到的blob 数据,最终用户通过this.responseText拿到的就是图片文件对应的二进制字符串,最后再将其转换为 blob 数据。

    xhr.responseType

    responseTypexhr level 2新增的属性,用来指定xhr.response的数据类型,目前还存在些兼容性问题,可以参考本文的【XMLHttpRequest的兼容性】这一小节。那么responseType可以设置为哪些格式呢,我简单做了一个表,如下:

    xhr.response 数据类型说明
    ""String字符串默认值(在不设置responseType时)
    "text"String字符串
    "document"Document对象希望返回 XML 格式数据时使用
    "json"javascript 对象存在兼容性问题,IE10/IE11不支持
    "blob"Blob对象
    "arrayBuffer"ArrayBuffer对象

    下面是同样是获取一张图片的代码示例,相比xhr.overrideMimeType,用xhr.response来实现简单得多。

    var xhr = new XMLHttpRequest();
    xhr.open('GET', '/path/to/image.png', true);
    //可以将`xhr.responseType`设置为`"blob"`也可以设置为`" arrayBuffer"`
    //xhr.responseType = 'arrayBuffer';
    xhr.responseType = 'blob';
    
    xhr.onload = function(e) {
      if (this.status == 200) {
        var blob = this.response;
        ...
      }
    };
    
    xhr.send();

    小结

    虽然在xhr level 2中,2者是共同存在的。但其实不难发现,xhr.responseType就是用来取代xhr.overrideMimeType()的,xhr.responseType功能强大的多,xhr.overrideMimeType()能做到的xhr.responseType都能做到。所以我们现在完全可以摒弃使用xhr.overrideMimeType()了。

    如何获取response数据

    xhr提供了3个属性来获取请求返回的数据,分别是:xhr.responsexhr.responseTextxhr.responseXML

    • xhr.response

      • 默认值:空字符串""

      • 当请求完成时,此属性才有正确的值

      • 请求未完成时,此属性的值可能是""或者 null,具体与 xhr.responseType有关:当responseType"""text"时,值为""responseType为其他值时,值为 null

    • xhr.responseText

      • 默认值为空字符串""

      • 只有当 responseType 为"text"""时,xhr对象上才有此属性,此时才能调用xhr.responseText,否则抛错

      • 只有当请求成功时,才能拿到正确值。以下2种情况下值都为空字符串"":请求未完成、请求失败

    • xhr.responseXML

      • 默认值为 null

      • 只有当 responseType 为"text""""document"时,xhr对象上才有此属性,此时才能调用xhr.responseXML,否则抛错

      • 只有当请求成功且返回数据被正确解析时,才能拿到正确值。以下3种情况下值都为null:请求未完成、请求失败、请求成功但返回数据无法被正确解析时

    如何追踪ajax请求的当前状态

    在发一个ajax请求后,如果想追踪请求当前处于哪种状态,该怎么做呢?

    xhr.readyState这个属性即可追踪到。这个属性是只读属性,总共有5种可能值,分别对应xhr不同的不同阶段。每次xhr.readyState的值发生变化时,都会触发xhr.onreadystatechange事件,我们可以在这个事件中进行相关状态判断。

      xhr.onreadystatechange = function () {
        switch(xhr.readyState){
          case 1://OPENED
            //do something
                break;
          case 2://HEADERS_RECEIVED
            //do something
            break;
          case 3://LOADING
            //do something
            break;
          case 4://DONE
            //do something
            break;
        }
    状态描述
    0UNSENT (初始状态,未打开)此时xhr对象被成功构造,open()方法还未被调用
    1OPENED (已打开,未发送)open()方法已被成功调用,send()方法还未被调用。注意:只有xhr处于OPENED状态,才能调用xhr.setRequestHeader()xhr.send(),否则会报错
    2HEADERS_RECEIVED(已获取响应头)send()方法已经被调用, 响应头和响应状态已经返回
    3LOADING (正在下载响应体)响应体(response entity body)正在下载中,此状态下通过xhr.response可能已经有了响应数据
    4DONE (整个数据传输过程结束)整个数据传输过程结束,不管本次请求是成功还是失败

    如何设置请求的超时时间

    如果请求过了很久还没有成功,为了不会白白占用的网络资源,我们一般会主动终止请求。XMLHttpRequest提供了timeout属性来允许设置请求的超时时间。

    xhr.timeout

    单位:milliseconds 毫秒
    默认值:0,即不设置超时

    很多同学都知道:从请求开始 算起,若超过 timeout 时间请求还没有结束(包括成功/失败),则会触发ontimeout事件,主动结束该请求。

    【那么到底什么时候才算是请求开始 ?】
    ——xhr.onloadstart事件触发的时候,也就是你调用xhr.send()方法的时候。
    因为xhr.open()只是创建了一个连接,但并没有真正开始数据的传输,而xhr.send()才是真正开始了数据的传输过程。只有调用了xhr.send(),才会触发xhr.onloadstart 。

    【那么什么时候才算是请求结束 ?】
    —— xhr.loadend事件触发的时候。

    另外,还有2个需要注意的坑儿:

    1. 可以在 send()之后再设置此xhr.timeout,但计时起始点仍为调用xhr.send()方法的时刻。

    2. xhr为一个sync同步请求时,xhr.timeout必须置为0,否则会抛错。原因可以参考本文的【如何发一个同步请求】一节。

    如何发一个同步请求

    xhr默认发的是异步请求,但也支持发同步请求(当然实际开发中应该尽量避免使用)。到底是异步还是同步请求,由xhr.open()传入的async参数决定。

    open(method, url [, async = true [, username = null [, password = null]]])

    • method: 请求的方式,如GET/POST/HEADER等,这个参数不区分大小写

    • url: 请求的地址,可以是相对地址如example.php,这个相对是相对于当前网页的url路径;也可以是绝对地址如http://www.example.com/example.php

    • async: 默认值为true,即为异步请求,若async=false,则为同步请求

    在我认真研读W3C 的 xhr 标准前,我总以为同步请求和异步请求只是阻塞和非阻塞的区别,其他什么事件触发、参数设置应该是一样的,事实证明我错了。

    W3C 的 xhr标准中关于open()方法有这样一段说明:

    Throws an "InvalidAccessError" exception if async is false, the JavaScript global environment is a document environment, and either the timeout attribute is not zero, the withCredentials attribute is true, or the responseType attribute is not the empty string.

    从上面一段说明可以知道,当xhr为同步请求时,有如下限制:

    • xhr.timeout必须为0

    • xhr.withCredentials必须为 false

    • xhr.responseType必须为""(注意置为"text"也不允许)

    若上面任何一个限制不满足,都会抛错,而对于异步请求,则没有这些参数设置上的限制。

    之前说过页面中应该尽量避免使用sync同步请求,为什么呢?
    因为我们无法设置请求超时时间(xhr.timeout0,即不限时)。在不限制超时的情况下,有可能同步请求一直处于pending状态,服务端迟迟不返回响应,这样整个页面就会一直阻塞,无法响应用户的其他交互。

    另外,标准中并没有提及同步请求时事件触发的限制,但实际开发中我确实遇到过部分应该触发的事件并没有触发的现象。如在 chrome中,当xhr为同步请求时,在xhr.readyState2变成3时,并不会触发 onreadystatechange事件,xhr.upload.onprogress和 xhr.onprogress事件也不会触发。

    如何获取上传、下载的进度

    在上传或者下载比较大的文件时,实时显示当前的上传、下载进度是很普遍的产品需求。
    我们可以通过onprogress事件来实时显示进度,默认情况下这个事件每50ms触发一次。需要注意的是,上传过程和下载过程触发的是不同对象的onprogress事件:

    • 上传触发的是xhr.upload对象的 onprogress事件

    • 下载触发的是xhr对象的onprogress事件

    xhr.onprogress = updateProgress;
    xhr.upload.onprogress = updateProgress;
    function updateProgress(event) {
        if (event.lengthComputable) {
          var completedPercent = event.loaded / event.total;
        }
     }

    可以发送什么类型的数据

    void send(data);

    xhr.send(data)的参数data可以是以下几种类型:

    • ArrayBuffer

    • Blob

    • Document

    • DOMString

    • FormData

    • null

    如果是 GET/HEAD请求,send()方法一般不传参或传 null。不过即使你真传入了参数,参数也最终被忽略,xhr.send(data)中的data会被置为 null.

    xhr.send(data)中data参数的数据类型会影响请求头部content-type的默认值:

    • 如果data是 Document 类型,同时也是HTML Document类型,则content-type默认值为text/html;charset=UTF-8;否则为application/xml;charset=UTF-8

    • 如果data是 DOMString 类型,content-type默认值为text/plain;charset=UTF-8

    • 如果data是 FormData 类型,content-type默认值为multipart/form-data; boundary=[xxx]

    • 如果data是其他类型,则不会设置content-type的默认值

    当然这些只是content-type的默认值,但如果用xhr.setRequestHeader()手动设置了中content-type的值,以上默认值就会被覆盖。

    另外需要注意的是,若在断网状态下调用xhr.send(data)方法,则会抛错:Uncaught NetworkError: Failed to execute 'send' on 'XMLHttpRequest'。一旦程序抛出错误,如果不 catch 就无法继续执行后面的代码,所以调用 xhr.send(data)方法时,应该用 try-catch捕捉错误。

    try{
        xhr.send(data)
      }catch(e) {
        //doSomething...
      };

    xhr.withCredentials与 CORS 什么关系

    我们都知道,在发同域请求时,浏览器会将cookie自动加在request header中。但大家是否遇到过这样的场景:在发送跨域请求时,cookie并没有自动加在request header中。

    造成这个问题的原因是:在CORS标准中做了规定,默认情况下,浏览器在发送跨域请求时,不能发送任何认证信息(credentials)如"cookies"和"HTTP authentication schemes"。除非xhr.withCredentialstruexhr对象有一个属性叫withCredentials,默认值为false)。

    所以根本原因是cookies也是一种认证信息,在跨域请求中,client端必须手动设置xhr.withCredentials=true,且server端也必须允许request能携带认证信息(即response header中包含Access-Control-Allow-Credentials:true),这样浏览器才会自动将cookie加在request header中。

    另外,要特别注意一点,一旦跨域request能够携带认证信息,server端一定不能将Access-Control-Allow-Origin设置为*,而必须设置为请求页面的域名。

    xhr相关事件

    事件分类

    xhr相关事件有很多,有时记起来还挺容易混乱。但当我了解了具体代码实现后,就容易理清楚了。下面是XMLHttpRequest的部分实现代码:

    interface XMLHttpRequestEventTarget : EventTarget {
      // event handlers
      attribute EventHandler onloadstart;
      attribute EventHandler onprogress;
      attribute EventHandler onabort;
      attribute EventHandler onerror;
      attribute EventHandler onload;
      attribute EventHandler ontimeout;
      attribute EventHandler onloadend;
    };
    
    interface XMLHttpRequestUpload : XMLHttpRequestEventTarget {
    
    };
    
    interface XMLHttpRequest : XMLHttpRequestEventTarget {
      // event handler
      attribute EventHandler onreadystatechange;
      readonly attribute XMLHttpRequestUpload upload;
    };

    从代码中我们可以看出:

    1. XMLHttpRequestEventTarget接口定义了7个事件:

      • onloadstart

      • onprogress

      • onabort

      • ontimeout

      • onerror

      • onload

      • onloadend

    2. 每一个XMLHttpRequest里面都有一个upload属性,而upload是一个XMLHttpRequestUpload对象

    3. XMLHttpRequestXMLHttpRequestUpload都继承了同一个XMLHttpRequestEventTarget接口,所以xhrxhr.upload都有第一条列举的7个事件

    4. onreadystatechangeXMLHttpRequest独有的事件

    所以这么一看就很清晰了:
    xhr一共有8个相关事件:7个XMLHttpRequestEventTarget事件+1个独有的onreadystatechange事件;而xhr.upload只有7个XMLHttpRequestEventTarget事件。

    事件触发条件

    下面是我自己整理的一张xhr相关事件触发条件表,其中最需要注意的是 onerror 事件的触发条件。

    事件触发条件
    onreadystatechange每当xhr.readyState改变时触发;但xhr.readyState由非0值变为0时不触发。
    onloadstart调用xhr.send()方法后立即触发,若xhr.send()未被调用则不会触发此事件。
    onprogressxhr.upload.onprogress在上传阶段(即xhr.send()之后,xhr.readystate=2之前)触发,每50ms触发一次;xhr.onprogress在下载阶段(即xhr.readystate=3时)触发,每50ms触发一次。
    onload当请求成功完成时触发,此时xhr.readystate=4
    onloadend当请求结束(包括请求成功和请求失败)时触发
    onabort当调用xhr.abort()后触发
    ontimeoutxhr.timeout不等于0,由请求开始即onloadstart开始算起,当到达xhr.timeout所设置时间请求还未结束即onloadend,则触发此事件。
    onerror在请求过程中,若发生Network error则会触发此事件(若发生Network error时,上传还没有结束,则会先触发xhr.upload.onerror,再触发xhr.onerror;若发生Network error时,上传已经结束,则只会触发xhr.onerror)。注意,只有发生了网络层级别的异常才会触发此事件,对于应用层级别的异常,如响应返回的xhr.statusCode4xx时,并不属于Network error,所以不会触发onerror事件,而是会触发onload事件。

    事件触发顺序

    当请求一切正常时,相关的事件触发顺序如下:

    1. 触发xhr.onreadystatechange(之后每次readyState变化时,都会触发一次)

    2. 触发xhr.onloadstart
      //上传阶段开始:

    3. 触发xhr.upload.onloadstart

    4. 触发xhr.upload.onprogress

    5. 触发xhr.upload.onload

    6. 触发xhr.upload.onloadend
      //上传结束,下载阶段开始:

    7. 触发xhr.onprogress

    8. 触发xhr.onload

    9. 触发xhr.onloadend

    发生abort/timeout/error异常的处理

    在请求的过程中,有可能发生 abort/timeout/error这3种异常。那么一旦发生这些异常,xhr后续会进行哪些处理呢?后续处理如下:

    1. 一旦发生aborttimeouterror异常,先立即中止当前请求

    2. 将 readystate 置为4,并触发 xhr.onreadystatechange事件

    3. 如果上传阶段还没有结束,则依次触发以下事件:

      • xhr.upload.onprogress

      • xhr.upload.[onabort或ontimeout或onerror]

      • xhr.upload.onloadend

    4. 触发 xhr.onprogress事件

    5. 触发 xhr.[onabort或ontimeout或onerror]事件

    6. 触发xhr.onloadend 事件

    在哪个xhr事件中注册成功回调?

    从上面介绍的事件中,可以知道若xhr请求成功,就会触发xhr.onreadystatechangexhr.onload两个事件。 那么我们到底要将成功回调注册在哪个事件中呢?我倾向于 xhr.onload事件,因为xhr.onreadystatechange是每次xhr.readyState变化时都会触发,而不是xhr.readyState=4时才触发。

    xhr.onload = function () {
        //如果请求成功
        if(xhr.status == 200){
          //do successCallback
        }
      }

    上面的示例代码是很常见的写法:先判断http状态码是否是200,如果是,则认为请求是成功的,接着执行成功回调。这样的判断是有坑儿的,比如当返回的http状态码不是200,而是201时,请求虽然也是成功的,但并没有执行成功回调逻辑。所以更靠谱的判断方法应该是:当http状态码为2xx304时才认为成功。

      xhr.onload = function () {
        //如果请求成功
        if((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304){
          //do successCallback
        }
      }
    展开全文
  • XMLHttpRequest

    千次阅读 2019-07-15 23:36:17
    XMLHttpRequest 使用XMLHttpRequest (XHR)对象可以与服务器交互。您可以从URL获取数据,而无需让整个的页面刷新。这使得Web页面可以只更新页面的局部,而不影响用户的操作。XMLHttpRequest在 Ajax 编程中被大量使用...

    XMLHttpRequest

    使用XMLHttpRequest (XHR)对象可以与服务器交互。您可以从URL获取数据,而无需让整个的页面刷新。这使得Web页面可以只更新页面的局部,而不影响用户的操作。XMLHttpRequest在 Ajax 编程中被大量使用。

    onreadystatechange 事件

    只要 readyState 属性发生变化,就会调用相应的处理函数。这个回调函数会被用户线程所调用。XMLHttpRequest.onreadystatechange 会在 XMLHttpRequest 的readyState 属性发生改变时触发 readystatechange 事件的时候被调用。

    • 属性

    XMLHttpRequest.onreadystatechange
    当readyState属性发生变化时调用的EventHandler。

    XMLHttpRequest.readyState 只读
    返回 一个unsigned short 即无符号短整型,请求的状态码。

    状态 描述
    0 UNSENT 代理被创建,但尚未调用 open() 方法。
    1 OPENED open() 方法已经被调用。
    2 HEADERS_RECEIVED send() 方法已经被调用,并且头部和状态已经可获得。
    3 LOADING 下载中; responseText 属性已经包含部分数据。
    4 DONE 下载操作已完成。

    XMLHttpRequest.response 只读
    返回ArrayBuffer、Blob、Document、DOMString,具体是哪种类型取决于XMLHttpRequest.responseType的值。其中包含响应体body。

    XMLHttpRequest.responseText 只读
    返回一个DOMString,该DOMString包含对请求的响应,如果请求未成功或尚未发送,则返回null。

    XMLHttpRequest.responseType
    定义响应类型的枚举值。

    描述
    “” 将 responseType 设为空字符串与设置为"text"相同, 是默认类型 (实际上是 DOMString)。
    “arraybuffer” response 是一个包含二进制数据的 JavaScript ArrayBuffer 。
    “blob” response 是一个包含二进制数据的 Blob 对象 。
    “document” response 是一个 HTML Document 或 XML XMLDocument ,这取决于接收到的数据的 MIME 类型。请参阅 HTML in XMLHttpRequest 以了解使用 XHR 获取 HTML 内容的更多信息。
    “json” response 是一个 JavaScript 对象。这个对象是通过将接收到的数据类型视为 JSON 解析得到的。
    “text” response 是包含在 DOMString 对象中的文本。
    “moz-chunked-arraybuffer” 与"arraybuffer"相似,但是数据会被接收到一个流中。使用此响应类型时,响应中的值仅在 progress 事件的处理程序中可用,并且只包含上一次响应 progress 事件以后收到的数据,而不是自请求发送以来收到的所有数据。在 progress 事件处理时访问 response 将返回到目前为止收到的数据。在 progress 事件处理程序之外访问, response 的值会始终为 null 。
    “ms-stream” response 是下载流的一部分;此响应类型仅允许下载请求,并且仅受Internet Explorer支持。

    XMLHttpRequest.responseURL 只读
    返回响应的序列化URL,如果URL为空,则返回空字符串。

    XMLHttpRequest.responseXML 只读
    返回一个Document,其中包含该请求的响应,如果请求未成功、尚未发送或不能解析为XML或HTML,则返回null。

    XMLHttpRequest.status 只读
    返回 unsigned short 即无符号短整型请求响应状态。

    XMLHttpRequest.statusText 只读
    返回一个DOMString},其中包含HTTP服务器返回的响应状态。与 XMLHTTPRequest.status不同的是,它包括响应状态的整个文本(例如,“200 OK”)。

    XMLHttpRequest.timeout
    unsigned long 即无符号长整型,表示该请求的最大请求时间(毫秒),超过该时间请求会自动结束。

    XMLHttpRequestEventTarget.ontimeout
    当请求超时调用的EventHandler。

    XMLHttpRequest.upload 只读
    XMLHttpRequestUpload,表示上传过程。
    可以被绑定在upload对象上的事件监听器如下:

    事件 相应属性的信息类型
    onloadstart 获取开始
    onprogress 数据传输进行中
    onabort 获取操作终止
    onerror 获取失败
    onload 获取成功
    ontimeout 获取操作在用户规定的时间内未完成
    onloadend 获取完成(不论成功与否)

    XMLHttpRequest.withCredentials
    Boolean,用来指定跨域的请求是否应该使用证书(如cookie或授权header头)。

    XMLHttpRequest.channel 只读
    nsIChannel,对象在执行请求时使用的通道。

    XMLHttpRequest.mozAnon 只读
    一个布尔值,如果为真,请求将在没有cookie和身份验证header头的情况下发送。

    XMLHttpRequest.mozSystem 只读
    一个布尔值,如果为真,则在请求时不会强制执行同源策略。

    XMLHttpRequest.mozBackgroundRequest
    一个布尔值,它指示对象是否是后台服务器端的请求

    • 方法

    XMLHttpRequest.abort()
    如果请求已经被发送,则立刻中止请求.

    XMLHttpRequest.getAllResponseHeaders()
    以字符串的形式返回所有用CRLF分隔的响应头,如果没有收到响应,则返回null。

    XMLHttpRequest.getResponseHeader(header)
    返回包含指定响应头的字符串,如果响应尚未收到或响应中不存在该报头,则返回null。

    XMLHttpRequest.open(method, url, async, user, password)
    初始化一个请求。该方法只能JavaScript代码中使用,若要在native code中初始化请求,请使用openRequest()。
    参数:

    参数 描述
    method 要使用的HTTP方法,比如「GET」、「POST」、「PUT」、「DELETE」、等。对于非HTTP(S) URL被忽略。
    url 一个DOMString表示要向其发送请求的URL。
    async 可选 一个可选的布尔参数,默认为true,表示要不要异步执行操作。如果值为false,send()方法直到收到答复前不会返回。如果true,已完成事务的通知可供事件监听器使用。如果multipart属性为true则这个必须为true,否则将引发异常。注意:从Gecko 30.0 (Firefox 30.0 / Thunderbird 30.0 / SeaMonkey 2.27)开始,由于对用户体验的负面影响,主线程上的同步请求已不赞成。
    user 可选 可选的用户名用于认证用途;默认为null。
    password 可选 可选的密码用于认证用途,默认为null。

    XMLHttpRequest.overrideMimeType('text/plain; charset=x-user-defined')
    重写由服务器返回的MIME type。

    XMLHttpRequest.send()
    发送请求。如果请求是异步的(默认),那么该方法将在请求发送后立即返回。

    XMLHttpRequest.setRequestHeader(header, value)
    设置HTTP请求头的值。您必须在open()之后、send()之前调用setRequestHeader()这个方法。

    XMLHttpRequest.sendAsBinary()
    send()方法的变体,用来发送二进制数据。

    • 示列
    var url = "";
    var xhr = new XMLHttpRequest();
    xhr.open('GET', url, true);
    xhr.responseType = "blob";
    xhr.setRequestHeader("client_type", "DESKTOP_WEB");
    xhr.setRequestHeader("desktop_web_access_key", _desktop_web_access_key);
    xhr.onreadystatechange = function() {
    	if (this.status == 200) {
    		var blob = this.response;
    		var img = document.createElement("img");
    		img.onload = function(e) {
    			window.URL.revokeObjectURL(img.src); 
    		}
    		img.src = window.URL.createObjectURL(blob);
    		$("#imgcontainer").html(img);    
    	}
    }
    xhr.send();
    
    展开全文
  • Javascript 内置方法之 - XMLHttpRequest

    千次阅读 2018-08-02 18:23:11
    XMLHttpRequestXMLHttpRequest 为 ajax 的核心。 使用 var xhr = new XMLHttpRequest() XMLHttpRequest 本质及构成 本质为一个函数; typeof XMLHttpRequest ; // 'function' 原型链关系:...
  • XMLHttpRequest的兼容性

    千次阅读 2018-10-25 18:08:41
    var request; if(Windows.XMLHttpRequest) {  request=new XMLHttpRequest(); } else {  request=new ActiveXObject("Microsoft.XMLHTTP"); //IE 5,IE6 }
  • XMLHttpRequest.send()

    万次阅读 2019-03-14 18:12:40
    XMLHttpRequest.send()方法用于实际发出 HTTP 请求。...如果带有参数,就表示除了头信息,还带有包含具体数据的信息体,典型例子就是 POST 请求。...var xhr = new XMLHttpRequest(); xhr.open('GET...
  • XMLHttpRequest对象属性及常用方法

    千次阅读 2018-11-23 14:09:40
    XMLHttpRequest是Ajax主要应用于处理发送异步处理请求和回应的,用户在后台和服务器交换数据,它有以下几个属性 1、readyState 每次这个属性的值增加的时候,都会触发 onreadystatechange 事件。该事件用于指定...
  • Synchronous XMLHttpRequest on the main thread is deprecated 原因是你的ajax执行了同步操作,即async设置为False,当然它并不影响程序的运行,但是右边有一道黄杠确实令人不爽,建议还是改成True为好(不设置...
  • abort方法在所有的XMLHttpRequest版本和XHR2中可用,调用abort方法在这个对象上触发abort事件//终止请求和超时 function timeedGetText(url,timeout,callback){ var xhr = new XMLHttpRequest();
  • 使用JavaScript的XMLHttpRequest发送请求

    万次阅读 2009-02-05 01:43:00
    使用XMLHttpRequest对象分为4部完成: 1.创建XMLHttpRequest组建 2.设置回调函数 3.初始化XMLHttpRequest组建 4.发送请求 实例代码: var userName; var passWord; var xmlHttpRequest; //XmlHttpRequest对象...
  • Failed to execute 'open' on 'XMLHttpRequest': Invalid URL 解决办法就是在请求的地址上加上http://
  • 使用XMLHttpRequest对象分为4部分完成: 1.创建XMLHttpRequest组建。 2.设置回调函数。 3.初始化XMLHttpRequest组建。 4.发送请求。   var userName; var passWord; var xmlHttpRequest; //...
  • 今天,我在执行js代码时遇到了如下错误:这表明这时候你的数据已经传进来了,但没法读出来。解决方法如下:步骤一:打开控制面板步骤二:点击网络和...本篇博客参考教程:XMLHttpRequest: 网络错误 0x80700013的...
  • XMLHttpRequest获取后台response返回的数据 开发MVC网站的过程中遇到令人头疼的bug——在js中通过XMLHttpRequest获取后台返回的数据竟然是当前页面的Html代码!!! 后台Controller: public class ...
  • Title xmlhttp function getHttpObj() { var httpobj = null; try { httpobj = new ActiveXObject("Msxml2.XMLHTTP"); } catch (e) { try
  • 一直没搞定XMLHttpRequest post方法如何传递多种参数,比如同时读取post参数和file参数  var http = new XMLHttpRequest();  var form = new FormData();  // Add selected file to form  form.append(me....
  • 错误: Access to XMLHttpRequest at ‘http://localhost:3000/framework/create’ from origin ‘http://localhost:4200’ has been blocked by CORS policy: Response to preflight request doesn’t pass access ...
  • XMLHttpRequest下载并生成文件

    万次阅读 2017-09-11 17:13:54
    是用XMLHttpRequest自带的progress属性来监听加载进度,但期间产生了一个问题,XMLHttpRequest请求返回的内容无法生成我们需要的excel文件,故查阅资料后作了如下修改。 function download(url){ var xhh = new ...
  • 提示请求了一个不安全的脚本,结果发送ajax请求时,报出如下错误 ...Mixed Content: The page at 'https:.....” was loaded over HTTPS, but requested an insecure XMLHttpRequest endpoint 'http...
1 2 3 4 5 ... 20
收藏数 132,453
精华内容 52,981
关键字:

xmlhttprequest