XMLHttpRequest对象
XHR对象有一个readyState属性,表示当前处在请求/响应过程的哪个阶段
0:未初始化
1:已打开(open),已调用open()方法,未调用send()方法
2:已发送(send)已调用send()方法,尚未收到响应
3:接受中(Receiving),已经收到部分响应
4:完成(Complete),已经收到所有响应,可以使用
每次readyState从一个值变为另一个值,会触发readystatechange事件,可以借此机会检查readyState的值,一般来说,我们只关心readyState值是4,表示数据已经就绪
1 | var form = document.getElementById("myForm"); |
凭据请求:
默认情况下,跨域请求不提供凭据(cookie,HTTP认证和客户端SSL证书),可以通过withCredentials属性设置为true来表明请求会发送凭据,如果服务器允许待凭据的请求,那么可以在响应中包含如下HTTP头部:Access-Control-Allow-Credentials:true
如果发送了凭据请求而服务器返回的响应中没有这个头部,则浏览器不会把响应交给JavaScript,服务器也可以在预检请求的响应中发送这个HTTP头部,以表明这个源允许发送凭据请求
Fetch API
fetch()只有一个必须的参数input,这个参数是要获取的资源的URL,这个方法返回一个期约;
当你的服务端返回的数据是 JSON 格式时,你肯定希望 fetch 返回给你的是一个普通 JavaScript 对象,然而你拿到的是一个 Response 对象,而真正的请求结果 —— 即 response.body —— 则是一个 ReadableStream 。
此外, Response 还限制了响应内容的重复读取和转换,
1 | var button=document.querySelector('[type=button]') |
常见Fetch请求模式
发送JSON数据
1 | let payload=JSON.stringfy({foo:'bar'}); |
请求体中发送参数
1 | let payload='foo=bar&baz=qux'; |
发送文件:
fetch()序列化并发送文件字段中的文件
1 | let imageFormData=new FormData(); |
中断请求:
通过AbortController/AbortSignal对中断请求,调用AbortController.abort()会中断所有网络的传输
1 | let abortController=new AbortController(); |
Request对象
通过构造函数初始化Request对象,接收两个参数,第一个参数是一个input参数,一般是URL,第二个参数是一个init对象,没有在init对象中涉及的值会使用默认值
创建Request对象副本
- 创建Request构造函数
- 使用clone()方法
使用构造函数:
1 | let r1=new Request('http://foo.com'); |
使用clone
请求体被读取后再克隆会导致抛出TypeError
1 | let r=new Request('http://foo.com'); |
在fetch()中使用Request对象
如果有第二个参数init对象,也会覆盖传入请求对象的值
1 | let r=new Request('http://127.0.0.1:3007/api/login'); |
要基于包含请求体的相同Request对象多次调用fetch(),必须在第一次发送fetch()请求前调用clone()
1 | let r=new Request(...); |
Response对象
产生Response对象的主要方式是调用fetch(),它返回一个最后会解决Response对象的期约
响应状态信息
其它问题
- fetch 不支持同步请求
大家都知道同步请求阻塞页面交互,但事实上仍有不少项目在使用同步请求,可能是历史架构等等原因。如果你切换了 fetch 则无法实现这一点。
- fetch 不支持取消一个请求
使用 XMLHttpRequest 你可以用 xhr.abort() 方法取消一个请求(虽然这个方法也不是那么靠谱,同时是否真的「取消」还依赖于服务端的实现),但是使用 fetch 就无能为力了,至少目前是这样的。
- fetch 无法查看请求的进度
使用 XMLHttpRequest 你可以通过 xhr.onprogress 回调来动态更新请求的进度,而这一点目前 fetch 还没有原生支持。