12

XMLHTTPRequest属性、方法、事件整理大全。

xhr 对象的方法

  • open(method:string, url:string, async?:boolean=true, username?:string, password: string)

    • 用于创建 HTTP 请求,但请求并未发送。
    • method, 请求类型,如 GETPOST 等,大小写不敏感。
    • url, URL 地址
    • async, 是否异步,默认 true
      若为同步请求时

      • xhr.timeout值必须为 0。
      • xhr.withCredentials值必须为 false。
      • xhr.responseType值必须为"",(text 也不允许)。
    • username, 用户名,一般不用。
    • password, 密码,一般不用。
  • send(body?:Object=null)

    • 定义 HTTP 请求的数据( body ),当 methodGETHEAD 时,该参数忽略。body 可为 ArrayBufferBlob、Document(类似 XML 格式数据)、DOMString(字符串)、FormData(表单)。
      ArrayBuffer、Blob、Document、DOMString、Formdata 详细参考
      注意:body 参数会影响请求头部的 content-type 默认值。

      • 如果 dataDocument 类型,同时也是 HTML Document 类型,则 content-type 默认值为 text/html;charset=UTF-8 ;否则为 application/xml;charset=UTF-8;
      • 如果 dataDOMString 类型,content-type 默认值为 text/plain;charset=UTF-8
      • 如果 dataFormData 类型,content-type 默认值为 multipart/form-data; boundary=[xxx]
      • 如果 data 是其他类型,则不会设置 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...
      };
  • abort()

    • 若请求已发出,则会终止请求,并将 readyState 置为 0.
    • 调用后,应将 xhr 对象置为 null 以促进垃圾回收。由于内存原因,不建议重用 xhr 对象。
      扩展阅读:和浏览器异步请求取消相关的那些事
  • overrideMimeType(type:string)
    重写 response 的 content-type。功能如同 xhr.responseType,已可以摒弃。
  • setRequestHeader(header:string, value:string)

    • 设置请求 HTTP 请求头信息。如content-typecookieaccept-xxx等。
    • header 参数大小写不敏感。
    • 必须在open()方法后,send()方法前调用,否则会抛错。
    • 可调用多次,最终值不会覆盖,而是采用追加append方式。
    • 禁止设置以下请求头,否则会抛错。

      • Accept-Charset
      • Accept-Encoding
      • Access-Control-Request-Headers
      • Access-Control-Request-Method
      • Connection
      • Content-Length
      • Cookie
      • Cookie2
      • Date
      • DNT
      • Expect
      • Host
      • Keep-Alive
      • Origin
      • Referer
      • TE
      • Trailer
      • Transfer-Encoding
      • Upgrade
      • User-Agent
      • Via
  • getResponseHeader(header:string)

    • 获取某个指定 header 字段的值。
    • header 字段不区分大小写。
    • 有严格安全限制,详见getAllResponseHeaders方法。
  • getAllResponseHeaders()

    • 获取 response 中所有 header 字段。
    • 有严格安全限制。如下:

      • 无论跨域或同域请求,无法获取Set-CookieSet-Cookie2字段值。
      • 跨域请求,只可获取simple response headerAccess-Control-Expose-Headers(名词解释见下方),否则会报错:Refused to get unsafe header。故若想访问其他字段,需后端添加到 Access-Control-Expose-Headers 中。

        simple response header 包括的 header 字段有:Cache-Control,Content-Language,Content-Type,Expires,Last-Modified,Pragma
> `Access-Control-Expose-Headers`:跨域请求独有,同域请求无。该字段中列举的 `header` 字段为服务器允许暴露给客户端访问的字段。
> 句法:```Access-Control-Expose-Headers: <header-name>, <header-name>, ...```

xhr 的属性

  • readyState
    [只读属性]用于追踪 xhr 当前的状态,共有 5 种可能的值,分别对应 xhr不同的阶段。
    每次 readyState 值变化时,都会触发 xhr.onreadystatechange 事件。

    状态 描述
    0 UNSENT (初始状态,未打开) 此时 xhr 对象被成功构造, open() 方法还未被调用
    1 OPENED (已打开,未发送) open() 方法已被成功调用,send() 方法还未被调用。注意:只有 xhr 处于 OPENED 状态,才能调用 xhr.setRequestHeader()xhr.send() ,否则会报错
    2 HEADERS_RECEIVED (已获取响应头) send() 方法已经被调用, 响应头和响应状态已经返回
    3 LOADING (正在下载响应体) 响应体( response entity body )正在下载中,此状态下 xhr.response 可能已经有了响应数据
    4 DONE (整个数据传输过程结束) 整个数据传输过程结束,不管本次请求是成功还是失败
  • statusstatusText
    status 属性表示 HTTP 响应状态码,如 200302400等。
    statusText 属性表示 HTTP响应状态的描述文本,如 OKNot Found等。
    注意,在 xhr.onload 事件中,不能简单的判断 xhr.status === 200,因为 20x304HTTP 状态码也被认为是请求成功。
    参考以下代码:

      xhr.onload = function () {
      //如果请求成功
      if((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304){
        //do successCallback
      }
    }
  • responseTyperesponse
    可在 xhr.send() 前设置 responseType ,用于指定返回的响应数据类型。和 xhr.overrideMimeType() 方法效果相同,推荐使用 responseType

    • IE10/IE11 不支持 xhr.responseTypejson
    • 部分浏览器不支持 xhr.responseTypeblob

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

    • 默认值为空字符串 ""
    • 只有当 responseTypetext""时,xhr 对象上才有此属性,此时才能调用 xhr.responseText ,否则抛错。
    • 只有当请求成功时,才能拿到正确值。以下 2 种情况下值都为空字符串 "":请求未完成、请求失败。
  • responseXML

    • 默认值为 null
    • 只有当 responseTypetext""document时,xhr 对象上才有此属性,此时才能调用 xhr.responseXML,否则抛错。
    • 只有当请求成功且返回数据被正确解析时,才能拿到正确值。以下 3 种情况下值都为 null :请求未完成、请求失败、请求成功但返回数据无法被正确解析时。
  • upload

    • 是一个XMLHttpRequestUpload对象,用于收集传输信息。支持事件:

      • onloadstart
      • onprogress
      • onabort
      • ontimeout
      • onerror
      • onload
      • onloadend
        具体触发顺序及条件,参考事件章节
        其中,xhr.upload.onprogress在上传阶段(即xhr.send()之后,xhr.readystate=2之前)触发,每 50ms 触发一次。可获得上传信息、进度等。
        上述事件回调的参数为 XMLHttpRequestEventTarget 对象,详见 事件补充
  • timeout

    • 单位毫秒,默认值 0 ,即不设置超时。
    • 计时从onloadstart 事件触发开始(即xhr.send()开始),以onloadend 事件触发为结束。
    • 在 IE 中,只能在调用open()方法后send()方法前设置。其他浏览器无此限制,但仍然从xhr.send()方法调用计时。
    • 不能为同步请求设置 timeout ,否则会报错。
    • 早期较多浏览器不支持,可通过 setTImeOut 实现。
  • withCredentials
    boolean 类型,默认值 false, 用于跨域请求时将 cookie 加入到 request header

    xhr.withCredentialsCORS 什么关系
    我们都知道,在发同域请求时,浏览器会将 cookie 自动加在 request header 中。但在发送跨域请求时, cookie 并不会自动加在 request header 中。
    造成这个问题的原因:在 CORS 标准有如下规定,默认情况下,浏览器在发送跨域请求时,不能发送任何认证信息(credentials)如 cookiesHTTP authentication schemes 。除非 xhr.withCredentialstrue
    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 共有 8 个事件,分别如下:

  • onloadstart
  • onprogress
  • onabort
  • ontimeout
  • onerror
  • onload
  • onloadend
  • onreadystatechange
事件触发条件
引用自 你真的会使用 XMLHttpRequest 吗?
事件 触发条件
onreadystatechange 每当xhr.readyState改变时触发;但xhr.readyState由非 0 值变为 0 时不触发。
onloadstart 调用xhr.send()方法后立即触发,若xhr.send()未被调用则不会触发此事件。
onprogress xhr.upload.onprogress在上传阶段(即xhr.send()之后,xhr.readystate=2之前)触发,每 50ms 触发一次;xhr.onprogress在下载阶段(即xhr.readystate=3时)触发,每 50ms 触发一次。
onload 当请求成功完成时触发,此时xhr.readystate=4
onloadend 当请求结束(包括请求成功和请求失败)时触发
onabort 当调用xhr.abort()后触发
ontimeout xhr.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 时事件触发顺序
  1. 触发 xhr.onreadystatechange 事件,此时 readystate4
  2. 如果上传阶段还没有结束,则依次触发以下事件:

    • xhr.upload.onprogress
    • xhr.upload.[onabort或ontimeout或onerror]
    • xhr.upload.onloadend
  3. 触发 xhr.onprogress 事件
  4. 触发 xhr.[onabort或ontimeout或onerror] 事件
  5. 触发 xhr.onloadend 事件
事件补充

xhr.upload.onprogressxhr.onprogress 的回调参数为 XMLHttpRequestEventTarget 对象。属性如下:

  • lengthComputable
    【只读】,为 boolean值,表示资源是否有可计算的长度。
  • loaded
    已接收或已上传的字节数。
  • total
    文件总字节数。
  • xhr.upload.onprogress 事件触发于上传阶段,可用于获取上传进度。
  • xhr.onprogress 事件触发于下载阶段,可用于获取下载进度。

后续补充计划

  • fetchAPI 整理。
  • jQuery.ajax 的实现详解。
  • axios 的实现详解。

参考资料


Kyle
47 声望3 粉丝