共计 6672 个字符,预计需要花费 17 分钟才能阅读完成。
XMLHTTPRequest 属性、方法、事件整理大全。
xhr 对象的方法
-
open(method:string, url:string, async?:boolean=true, username?:string, password: string)
- 用于创建
HTTP
请求,但请求并未发送。 -
method
, 请求类型,如GET
、POST
等,大小写不敏感。 -
url
,URL
地址 -
async
, 是否异步,默认true
。
若为同步请求时-
xhr.timeout
值必须为 0。 -
xhr.withCredentials
值必须为 false。 -
xhr.responseType
值必须为""
,(text
也不允许)。
-
-
username
, 用户名,一般不用。 -
password
, 密码,一般不用。
- 用于创建
-
send(body?:Object=null)
-
定义
HTTP
请求的数据(body
),当method
为GET
、HEAD
时,该参数忽略。body
可为ArrayBuffer
、Blob、Document
(类似XML
格式数据)、DOMString
(字符串)、FormData
(表单)。
ArrayBuffer、Blob、Document、DOMString、Formdata 详细参考。
注意:body 参数会影响请求头部的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
的默认值如果用 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-type
、cookie
、accept-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
- 设置请求 HTTP 请求头信息。如
-
getResponseHeader(header:string)
- 获取某个指定 header 字段的值。
- header 字段不区分大小写。
- 有严格安全限制,详见
getAllResponseHeaders
方法。
-
getAllResponseHeaders()
- 获取 response 中所有 header 字段。
-
有严格安全限制。如下:
- 无论跨域或同域请求,无法获取
Set-Cookie
、Set-Cookie2
字段值。 -
跨域请求,只可获取 simple response header 和Access-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
(整个数据传输过程结束)整个数据传输过程结束,不管本次请求是成功还是失败 -
status
和statusText
status
属性表示HTTP
响应状态码,如200
、302
、400
等。statusText
属性表示HTTP
响应状态的描述文本,如OK
、Not Found
等。
注意 ,在xhr.onload
事件中,不能简单的判断xhr.status === 200
,因为20x
、304
等HTTP
状态码也被认为是请求成功。
参考以下代码:xhr.onload = function () { // 如果请求成功 if((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304){//do successCallback} }
-
responseType
和response
可在xhr.send()
前设置responseType
,用于指定返回的响应数据类型。和xhr.overrideMimeType()
方法效果相同,推荐使用responseType
。- IE10/IE11 不支持
xhr.responseType
为json
。 -
部分浏览器不支持
xhr.responseType
为blob
。值 描述 ""
将 responseType
设为空字符串与设置为text
相同,是默认类型(实际上是DOMString
)。arraybuffer
response
是一个包含二进制数据的JavaScript ArrayBuffer
。blob
response
是一个包含二进制数据的Blob
对象。document
response
是一个HTML Document
或XML 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
支持。
- IE10/IE11 不支持
-
responseText
- 默认值为空字符串
""
- 只有当
responseType
为text
、""
时,xhr
对象上才有此属性,此时才能调用xhr.responseText
,否则抛错。 - 只有当请求成功时,才能拿到正确值。以下
2
种情况下值都为空字符串""
:请求未完成、请求失败。
- 默认值为空字符串
-
responseXML
- 默认值为
null
- 只有当
responseType
为text
、""
、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.withCredentials
与CORS
什么关系
我们都知道,在发同域请求时,浏览器会将cookie
自动加在request header
中。但在发送跨域请求时,cookie
并不会自动加在request header
中。
造成这个问题的原因:在CORS
标准有如下规定,默认情况下,浏览器在发送跨域请求时,不能发送任何认证信息(credentials
)如cookies
和HTTP authentication schemes
。除非xhr.withCredentials
为true
。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.statusCode 是 4xx 时,并不属于 Network error ,所以不会触发 onerror 事件,而是会触发 onload 事件。 |
请求正常时,事件触发顺序
- 触发
xhr.onreadystatechange
(之后每次 readyState 变化时,都会触发一次) - 触发
xhr.onloadstart
// 上传阶段开始: - 触发
xhr.upload.onloadstart
- 触发
xhr.upload.onprogress
- 触发
xhr.upload.onload
- 触发
xhr.upload.onloadend
// 上传结束,下载阶段开始: - 触发
xhr.onprogress
- 触发
xhr.onload
- 触发
xhr.onloadend
发生 abort
/ timeout
/ error
时事件触发顺序
- 触发
xhr.onreadystatechange
事件,此时readystate
为4
-
如果上传阶段还没有结束,则依次触发以下事件:
xhr.upload.onprogress
xhr.upload.[onabort 或 ontimeout 或 onerror]
xhr.upload.onloadend
- 触发
xhr.onprogress
事件 - 触发
xhr.[onabort 或 ontimeout 或 onerror]
事件 - 触发
xhr.onloadend
事件
事件补充
xhr.upload.onprogress
和 xhr.onprogress
的回调参数为 XMLHttpRequestEventTarget
对象。属性如下:
-
lengthComputable
【只读】,为boolean
值,表示资源是否有可计算的长度。 -
loaded
已接收或已上传的字节数。 -
total
文件总字节数。 -
xhr.upload.onprogress
事件触发于上传阶段,可用于获取上传进度。 -
xhr.onprogress
事件触发于下载阶段,可用于获取下载进度。
后续补充计划
-
fetchAPI
整理。 -
jQuery.ajax
的实现详解。 -
axios
的实现详解。
参考资料
- DOMString、Document、FormData、Blob、File、ArrayBuffer 数据类型介绍
- 你真的会使用
XMLHttpRequest
吗? - XMLHttpRequest Level 2 使用指南