一、初识fetch
Fetch被称为下一代Ajax技术,采用Promise方式来处理数据。是一种简洁明了的API
,比XMLHttpRequest
更加简单易用。
XMLHttpRequest
我们先来看看使用纯XMLhttpRequest来实现一次简单ajax请求的代码:
//获取XMLHttpRequest实例对象
const xhr = new XMLHttpRequest();
//初始请求
xhr.open("get", "https://jsonplaceholder.typicode.com/users");
//发送数据
xhr.send();
//设置xhr请求状态修改回调
xhr.onreadystatechange = function () {
//如果请求状态已完成时
if (xhr.readyState === 4) {
//如果响应状态码大于等于200并且小于300时
if (xhr.status >= 200 && xhr.status < 300) {
//请求成功
console.log(JSON.parse(xhr.response));
} else {
//请求失败
console.log("请求失败!");
}
}
};
请不要把XMLHttpRequest和Ajax弄混了,Ajax只是一种思想或者技术,而XMLHttpRequest是一个原生对象,可以使用他实现Ajax。
fetch
Fetch 是一个现代的概念,等同于 XMLHttpRequest。它提供了许多与 XMLHttpRequest 相同的功能,但被设计成更具可扩展性和高效性。
注意,Fetch是JavaScript提供的原生API,所以是可以直接使用的,我们同样使用fetch来请求上一个例子的接口:
fetch("https://jsonplaceholder.typicode.com/users")
.then((res) => res.json())
.then((data) => console.log(data));
可以看到,fetch是返回的Promise实例,可以直接进行链式调用,代码更加简单易懂,也可以使用async和await。
Axios
Axios中文官网
其实可以发现,fetch和axios的使用方法十分相似,因为Axios的浏览器端其实就是XMLHttpRequest结合Promise
的封装结果。
因此,fetch其实是可以直接代替Axios来进行浏览器端发起请求的,直接用原生的!
二、fetch配置
既然说fetch可以代替axios,那么fetch肯定和axios一样,可以配置许多选项,来完成不同的请求,例如获取数据、修改数据、上传文件等等……
配置
Promise<Response> fetch(input[, init]);
第一个参数input是定义要获取的资源
。这可能是:
- 一个 USVString 字符串,包含要获取资源的 URL。一些浏览器会接受 blob: 和 data: 作为 schemes. 一个
- Request 对象。 fetch方法还可以接受第二个参数(可选),作为
配置对象
,定制发出的 HTTP 请求。
第二个参数(init)是可选参数对象:
fetch(url, {
method: "GET",//请求方法 默认get
headers: {//配置请求头
"Content-Type": "text/plain;charset=UTF-8"
},
body: data,//请求的 body 信息:可能是一个 Blob、BufferSource、FormData、URLSearchParams 或者 USVString 对象。注意 GET 或 HEAD 方法的请求不能包含 body 信息。
referrer: "about:client",// 一个 USVString 可以是 no-referrer、client 或一个 URL。默认是 client。
referrerPolicy: "no-referrer-when-downgrade",//指定了 HTTP 头部 referer 字段的值。可能为以下值之一:no-referrer、 no-referrer-when-downgrade、origin、origin-when-cross-origin、 unsafe-url。
mode: "cors",//请求的模式,如 cors、no-cors 或者 same-origin。
credentials: "same-origin",// 请求的 credentials,如 omit、same-origin 或者 include。为了在当前域名内自动发送 cookie,必须提供这个选项。
cache: "default",// 请求的 cache 模式:default、 no-store、 reload 、 no-cache、 force-cache 或者 only-if-cached。
redirect: "follow",//可用的 redirect 模式:follow (自动重定向), error (如果产生重定向将自动终止并且抛出一个错误),或者 manual (手动处理重定向)。在 Chrome 中默认使用 follow(Chrome 47 之前的默认值是 manual)
integrity: "",//包括请求的 subresource integrity 值(例如: sha256-BpfBw7ivV8q2jLiT13fxDYAe2tJllusRSZ273h2nFSE=)。
keepalive: false,//而这个参数是在说,即使页面已经不在了,这个请求依然需要完成,因此浏览器会延长它的生存期。
signal: undefined//配合AbortController完成请求中断操作
});
三、常用对象及方法
fetch()采用模块化设计,API 分散在多个对象上(Response 对象、Request 对象、Headers 对象),使得编写的代码更加合理,逻辑也更加清晰。
Request
Request MDN文档
前面说到fetch的第一个参数可以是一个Request对象。
var myRequest = new Request(input[, init]);
与fetch()的参数好像差不多。
实例方法
arrayBuffer()
Request 接口的 arrayBuffer() 方法读取请求体
并将其作为一个 promise 返回,该 promise 将兑现一个 ArrayBuffer
。
const myArray = new Uint8Array(10);
const request = new Request('/myEndpoint', {
method: 'POST',
body: myArray
});
request.arrayBuffer().then(function(buffer) {
// do something with the buffer sent in the request
});
blob()
Request 接口的 blob() 方法读取请求体并将其作为 promise 返回,该 promise 将兑现一个 Blob。
const obj = {hello: 'world'};
const myBlob = new Blob([JSON.stringify(obj, null, 2)], {type : 'application/json'});
const request = new Request('/myEndpoint', {
method: 'POST',
body: myBlob
});
request.blob().then(function(myBlob) {
// do something with the blob sent in the request
});
clone()
Request 接口中的clone() 方法可以创建一个当前Request 对象的副本。
formData
Request 接口的 formData() 方法读取请求体并将其作为 promise 返回,该 promise 将兑现一个 FormData 对象。
const formData = new FormData();
const fileField = document.querySelector('input[type="file"]');
formData.append('username', 'abc123');
formData.append('avatar', fileField.files[0]);
const request = new Request('/myEndpoint', {
method: 'POST',
body: formData
});
request.formData().then(function(data) {
// do something with the formdata sent in the request
});
json()
Request 接口的 json() 方法读取请求体并将其作为一个 promise 返回,该 promise 将兑现一个由响应体的文本解析得到的 JSON。
注意,尽管方法被命名为 json(),结果并不是 JSON,而是将输入作为 JSON 解析,以生成一个 JavaScript 对象
。
返回一个将兑现一个 JavaScript 对象的 Promise。这个对象可能是任何可以用 JSON 表示的东西——一个对象、一个数组、一个字符串、一个数值……
const obj = {hello: 'world'};
const request = new Request('/myEndpoint', {
method: 'POST',
body: JSON.stringify(obj)
});
request.json().then(function(data) {
// do something with the data sent in the request
});
text()
Request 接口的 text() 方法读取请求体并且将其作为一个 promise
返回,该 promise 将兑现一个 String。响应总是使用 UTF-8 解码。
Response
你可以使用 Response.Response() 构造函数来创建一个 Response 对象,但通常更可能遇到的情况是,其他的 API 操作返回了一个 Response 对象。
let r = new Response();
console.log(r);
// Response {
// body: (...)
// bodyUsed: false //包含了一个布尔值 (en-US)来标示该 Response 是否读取过 Body。
// headers: Headers {} //包含此 Response 所关联的 Headers 对象。
// ok: true //包含了一个布尔值,标示该 Response 成功(HTTP 状态码的范围在 200-299)。
// redirected: false //表示该 Response 是否来自一个重定向,如果是的话,它的 URL 列表将会有多个条目。
// status: 200 //包含 Response 的状态码(例如 200 表示成功)。
// statusText: "OK" //包含了与该 Response 状态码一致的状态信息(例如,OK 对应 200)。
// type: "default" //包含 Response 的类型(例如,basic、cors)。
// url: "" //包含 Response 的 URL。
// }
静态方法
error()
Response 接口的 error() 方法返回一个包含网络错误相关信息的新 Response 对象。
redirect()
Response 接口的 redirect() 方法返回一个可以重定向到指定 URL 的 Response 。
var response = Response.redirect(url, status);
实例方法
arrayBuffer
Response上的方法 arrayBuffer() 接受一个 Response 流,并等待其读取完成。它返回一个 promise 实例,并 resolve 一个 ArrayBuffer 对象。
response.arrayBuffer().then(function(buffer) {
// do something with buffer
)};
blob
Response mixin 的 **blob()**方法使用一个 Response 流,并将其读取完成。它返回一个使用Blob解决的 promise。
response.blob().then(function(myBlob) {
// do something with myBlob
});
clone
Response 接口的 clone() 方法创建一个响应对象的克隆,这个对象在所有方面都是相同的,但是储存在不同的变量中。
如果响应体已经被使用,clone() 抛出 TypeError。事实上,clone() 存在的主要原因是允许 body 对象可以使用多次(当它们是一次性使用时)。
const image1 = document.querySelector('.img1');
const image2 = document.querySelector('.img2');
const myRequest = new Request('flowers.jpg');
fetch(myRequest).then((response) => {
const response2 = response.clone();
response.blob().then((myBlob) => {
const objectURL = URL.createObjectURL(myBlob);
image1.src = objectURL;
});
response2.blob().then((myBlob) => {
const objectURL = URL.createObjectURL(myBlob);
image2.src = objectURL;
});
});
formData
Response 对象中的formData() 方法将 Response 对象中的所承载的数据流读取并封装成为一个对象,该方法将返回一个 Promise 对象,该对象将产生一个FormData 对象。
response.formData()
.then(function(formdata) {
// do something with your formdata
});
json
Response mixin 的 json() 方法接收一个 Response 流,并将其读取完成。它返回一个 Promise,Promise 的解析 resolve 结果是将文本体解析为 JSON。
response.json().then(data => {
// do something with your data
});
返回一个被解析为 JSON 格式的 promise 对象
,这可以是任何可以由 JSON 表示的东西
- 一个 object,一个 array,一个 string,一个 number…
text
Response mixin 的 text() 方法提供了一个可供读取的“返回流”(Response stream),并将它读取完。它返回一个包含 USVString 对象(也就是文本)的 Promise 对象,返回结果的编码永远是 UTF-8。
response.text().then(function (text) {
// do something with the text response
});
Headers
Fetch API 的 Headers 接口允许您对 HTTP 请求和响应头执行各种操作。这些操作包括检索,设置,添加和删除。一个 Headers 对象具有关联的头列表,它最初为空,由零个或多个键值对组成。
构造函数Headers()
var myHeaders = new Headers(init);
init 参数可选:通过一个包含任意 HTTP headers 的对象来预设你的 Headers. 可以是一个ByteString 对象
; 或者是一个已存在
的 Headers 对象。
append()
在一个Headers对象内部,Headers接口的 append() 方法可以追加一个新值到已存在的 headers 上,或者新增一个原本不存在的 header。
myHeaders.append(name,value);
delete()
delete() 方法可以从 Headers 对象中删除指定 header.
下列原因将会导致该方法抛出一个TypeError:
- header 名在 HTTP header 中是不存在的。
- header 被锁定了。
myHeaders.delete(name);
entries()
Headers.entries() 以 迭代器 的形式返回 Headers 对象中所有的键值对。
// Create a test Headers object
var myHeaders = new Headers();
myHeaders.append('Content-Type', 'text/xml');
myHeaders.append('Vary', 'Accept-Language');
// Display the key/value pairs
for (var pair of myHeaders.entries()) {
console.log(pair[0]+ ': '+ pair[1]);
}
forEach()
和遍历数组的forEach方法类似。
// Create a new test Headers object
const myHeaders = new Headers();
myHeaders.append("Content-Type", "application/json");
myHeaders.append("Cookie", "This is a demo cookie");
myHeaders.append("compression", "gzip");
// Display the key/value pairs
myHeaders.forEach((value, key) => {
console.log(`${key} ==> ${value}`);
})
返回
compression ==> gzip
content-type ==> application/json
cookie ==> This is a demo cookie
get()
获取指定headers属性的值。
const myHeaders = new Headers(); // Currently empty
myHeaders.get('Not-Set'); // Returns null
has()
Headers 接口的 **has()**方法返回一个布尔值来声明一个 Headers对象 是否包含特定的头信息。
myHeaders.append('Content-Type', 'image/jpeg');
myHeaders.has('Content-Type'); // Returns true
myHeaders.has('Accept-Encoding'); // Returns false
keys()
eaders.keys() 方法返回一个 headers(Object) 对象所有 key 组成的迭代器,通过迭代器可以遍历 headers 这个对象,返回的迭代器中的元素 key 都是字符串。
// 创建一个 Headers 对象
var myHeaders = new Headers();
myHeaders.append('Content-Type', 'text/xml');
myHeaders.append('Vary', 'Accept-Language');
// 显示 Headers 中所有的 key
for(var key of myHeaders.keys()) {
console.log(key);
}
set()
Headers.set 和 append() 两者之间的不同之处在于当指定 header 是已经存在的并且允许接收多个值时,Headers.set会重写此值为新值
,而append()会追加到值序列的尾部
。
myHeaders.set('Accept-Encoding', 'deflate');
myHeaders.set('Accept-Encoding', 'gzip');
myHeaders.get('Accept-Encoding'); // Returns 'gzip'
values()
Headers.values() 方法返回一个可迭代数值,通过这个数值可以遍历 Headers 中键值对的 value 值。返回的 value 都是 ByteString 对象。
// Create a test Headers object
var myHeaders = new Headers();
myHeaders.append('Content-Type', 'text/xml');
myHeaders.append('Vary', 'Accept-Language');
// Display the values
for (var value of myHeaders.values()) {
console.log(value);
}
text/xml
Accept-Language
以上内容全部参考于mdn web docs - Fetch API