XHR
和 fetch API
都是浏览器给上层使用者暴露出来的 API,都是建立在http协议上的,给使用者提供了部分系统操作 http
包的能力。
XMLHttpRequest
XHR
在1999年加入到 IE5 中,之后所有主流的浏览器都引入了该特性。AJAX
架构的出现使XHR
变得人尽皆知,XHR
对象用于与服务器交互。可以用于获取任何类型的数据,甚至支持HTTP以外的协议(包括 file:// 和 FTP)。
原始的XHR
使用方法
GET请求 👇
const xhr = new XMLHttpRequest();
xhr.open('GET', url);
xhr.responseType = 'json';
xhr.onload = function() {
console.log(xhr.response);
}
xhr.onerror = function() {
console.log('error');
}
xhr.send();
POST请求 👇
const convertToURL = function(obj) {
let result = '';
if(obj!== null && typeof obj === 'object') {
for(var key in obj) {
if(obj.hasOwnProperty(key)) {
let tmp = `&${key}=${obj[key]}`;
result += tmp;
}
}
result = result.substring(1);
}
return result;
}
const xhr = new XMLHttpRequest();
xhr.onreadystatechange = (res) => {
if (xhr.readyState === 4 && xhr.status === 200) {
console.log('success response', xhr.response);
}
};
xhr.open('post', '/listByPage');
const params = {
pageNum: 1,
pageSize: 10
};
xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
xhr.responseType = 'json';
xhr.send(convertToURL(params));
// 当设置为请求头的Content-Type设为application/json时,不能直接发送json对象,需要把json对象序列化才行。
// xhr.setRequestHeader('Content-Type', 'application/json;charset=UTF-8');
// xhr.send(JSON.stringify(params));
XHR的属性
XHR.readyState
== 状态(0,1,2,3,4),而且状态也是不可逆的:
- 0:请求未初始化,还没有调用 open()。
- 1:请求已经建立,但是还没有发送,还没有调用 send()。
- 2:请求已发送,正在处理中(通常现在可以从响应中获取内容头)。
- 3:请求在处理中;通常响应中已有部分数据可用了,没有全部完成。
- 4:响应已完成;您可以获取并使用服务器的响应了。
XHR.onreadystatechange
用来监听 XHR.readyState 变化
XHR.response
相应实体,类型取决于responseType
XHR.responseType
定义响应类型的枚举值,'arraybuffer'、'blob'、'document'、'json'、'text'、''(默认)。
XHR.status
请求的响应状态
XHR.timeout
设置请求最大请求事件,超出该时间请求自动终止。
XHR.ontimeout
设置请求超时的回调。
XHR.upload
只读,代表上传进度。
XHR的方法
XHR.open()
初始化一个请求。
XHR.abort()
终止请求。
XHR.send()
发送请求。
XHR.setRequestHeader()
设置HTTP请求头。
XHR.getAllResponseHeaders()
获取所有CRLF 分隔的响应头,如没有收到响应则返回null
。
XHR.getResponseHeader(key)
获取指定响应头的字符串,如果不存在该响应头或者响应未收到,则返回null
。
XHR的事件
XHR.error
当请求被停止时触发,例如程序调用XHR.abort()时。也可以使用XHR.onabort属性
XHR.error
当请求遇到错误时触发,也可以使用XHR.onerror属性
XHR.load
当请求成功完成时触发,也可以使用XHR.onload属性
XHR.loadstart
当接收到响应数据时触发,也可以使用XHR.onloadstart属性
XHR.loadend
当结束时触发无论请求是成功(load)还是失败(abort或error),也可以使用XHR.onloadend属性
XHR.progress
当请求接收到更多数据时,周期性地触发,也可以使用XHR.onprogress属性
XHR.timeout
在预设时间内没有接收到响应时触发。也可以使用 ontimeout 属性
XHR的不足
从使用方法上看,http的request和response以及事件监听都在同一个xhr对象上,代码组织缺少语义化且可能造成回调地狱,手写一个xhr还是比较麻烦的。于是出现了jQuery.ajax()
和 axios
都是基于XHR使用Promise
的方法设计的API,来避免回调的写法。
FETCH
fetch API
使用Promise语法结构。返回一个Promise,可以使用async/await,代码比原始的XHR清爽。
使用方法
GET请求
fetch(url)
.then( response => {
console.log(response.json());
})
.then( json => console.log(json) )
.catch( error => console.error('error:', error) );
POST请求
const url = '/listByPage';
const options = {
method: "POST",
headers: {
Accept: "application/json",
"Content-Type": "application/json;charset=UTF-8",
},
body: JSON.stringify({
pageNum: 1,
pageSize: 10
}),
};
fetch(url, options).then((response) => {
console.log(response.status);
});
fetch 可以接受两个参数input和init
fetch的input参数
它是一个 Request
对象或者是一个字符串,可以传一个 Request
实例
fetch的init参数
第二个参数可以接受一个对象。
method
请求的方法,如GET
POST
等headers
请求头信息body
请求的body信息,可以是Blob
、BufferSource
、FormData
、URLSearchParams
或者USVString
对象- mode 请求的模式,如
cors、no-cors
或者same-origin
。 credentials
: 请求的 credentials,如omit、``same-origin 或者
include
。为了在当前域名内自动发送 cookie ,必须提供这个选项。cache
: 请求的 cache 模式:default
、no-store
、reload
、no-cache
、force-cache
或者only-if-cached
。redirect
: 可用的 redirect 模式:follow
(自动重定向),error
(如果产生重定向将自动终止并且抛出一个错误), 或者manual
(手动处理重定向)。referrer
: 一个USVString
可以是no-referrer、``client
或一个 URL。默认是client。
referrerPolicy
: 指定了HTTP头部referer字段的值。可能为以下值之一:no-referrer、
no-referrer-when-downgrade、
origin、
origin-when-cross-origin、
unsafe-url 。
integrity
: 包括请求的 subresource integrity值。
fetch 的不足
默认不会发送cookies
默认无Cookie,需要设置init参数 credentials: 'same-origin'
请求错误不会reject
HTTP请求错误时,fetch返回的Promise不会被标记为reject,也不会执行catch。需要在resolve中判断response.ok是否为true。
fetch(url)
.then( response => {
if (response.ok) return response.json();
throw new Error('Network error');
})
.then( json => console.log(json) )
.catch( error => console.error('error:', error) );
没有timeout
fetch没有timeout配置,可以使用Promise.race()来设置超时。也可以通过signal参数来实现👇
Promise.race([
fetch('http://url', { method: 'GET' }),
new Promise(resolve => setTimeout(() => resolve('network error: timeout'), 3000))
])
.then(response => console.log(response))
没有abort
旧版的fetch一旦发起请求无法中指,现在支持 AbortController
API 的浏览器可以通过调用abortController.abort()
终止,Promise 会被标记为reject状态,同样可以实现 timeout 的效果。
const controller = new AbortController();
fetch(url, {
signal: controller.signal
})
.then( response => {
if (response.ok) return response.json();
throw new Error('Network error');
})
.then( json => console.log(json) )
.catch( error => console.error('error:', error) );
setTimeout(() => controller.abort(), 3000)
没有progress
不能显示文件上传和大型表单提交的进度
使用
很多网站的请求都包含fetch和xhr。
掘金:
bilibili
youtube
参考链接