文章目录
前言
目前我们大多数用到的网络请求方式就是使用 XMLHttpRequest
实现的。
fetch()
是 XMLHttpRequest 的升级版,用于在 JavaScript 脚本里面发出 HTTP 请求。
fetch
规范与 jQuery.ajax()
主要有以下的不同:
- 当接收到一个代表错误的 HTTP 状态码时,从
fetch()
返回的 Promise 不会被标记为 reject,即使响应的 HTTP 状态码是 404 或 500。相反,它会将 Promise 状态标记为 resolve(如果响应的 HTTP 状态码不在 200 - 299 的范围内,则设置 resolve 返回值的ok
属性为 false),仅当网络故障时或请求被阻止时,才会标记为 reject。 fetch
不会发送跨域 cookie,除非你使用了 credentials 的初始化配置。fetch()
通过数据流(Stream 对象)处理数据,可以分块读取,有利于提高网站性能表现,减少内存占用,对于请求大文件或者网速慢的场景相当有用。XMLHTTPRequest 对象不支持数据流,所有的数据必须放在缓存里,不支持分块读取,必须等待全部拿到后,再一次性吐出来。
基本用法
全局的 fetch()
方法用于发起获取资源的请求。它返回一个 promise,这个 promise 会在请求响应后被 resolve,并传回 Response
对象。
如下:
Promise<Response> fetch(input[, init]);
第一个参数可以是一个字符串,包含要获取资源的 URL。一些浏览器会接受 blob:
和 data:
作为 schemes.
也可以是一个 Request
对象。
第二个参数就是一个配置项对象,包括所有对请求的设置。可选的参数有:
- method:请求使用的方法,如GET、POST等。
- headers:请求的头信息,形式为
Headers
的对象或包含ByteString
值的对象字面量。 - body:请求的 body 信息:可能是一个
Blob
、BufferSource
、FormData
、URLSearchParams
或者USVString
对象。注意 GET 或 HEAD 方法的请求不能包含 body 信息。 - mode: 请求的模式,如
cors
、no-cors
或者same-origin
。 - credentials:请求的 credentials,如
omit
、same-origin
或者include
。为了在当前域名内自动发送 cookie,必须提供这个选项,从 Chrome 50 开始,这个属性也可以接受FederatedCredential
实例或是一个PasswordCredential
实例。 - cache: 请求的 cache 模式:
default
、no-store
、reload
、no-cache
、force-cache
或者only-if-cached
。 - redirect: 可用的 redirect 模式:
follow
(自动重定向),error
(如果产生重定向将自动终止并且抛出一个错误),或者manual
(手动处理重定向)。在 Chrome 中默认使用follow
(Chrome 47 之前的默认值是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 值(例如:
sha256-BpfBw7ivV8q2jLiT13fxDYAe2tJllusRSZ273h2nFSE=
)。
一个基本的 fetch 请求设置起来很简单。看看下面的代码:
fetch('http://example.com/movies.json')
.then(response => response.json())
.then(data => console.log(data));
如上是一个简单的fetch请求,只设置了第一个参数。
接下来是设置第二个参数的fetch请求例子;
// Example POST method implementation:
async function postData(url = '', data = {}) {
// Default options are marked with *
try {
const response = await fetch(url, {
method: 'POST', // *GET, POST, PUT, DELETE, etc.
mode: 'cors', // no-cors, *cors, same-origin
cache: 'no-cache', // *default, no-cache, reload, force-cache, only-if-cached
credentials: 'same-origin', // include, *same-origin, omit
headers: {
'Content-Type': 'application/json'
// 'Content-Type': 'application/x-www-form-urlencoded',
},
redirect: 'follow',
referrerPolicy: 'no-referrer',
body: JSON.stringify(data)
});
return response.json();
} catch (error) {
console.log(error)
}
}
postData('https://example.com/answer', { answer: 42 })
.then(data => {
console.log(data); // JSON data parsed by `data.json()` call
});
注意:假如mode是no-cors,则允许使用一组有限的 HTTP 请求头:
Accept
Accept-Language
Content-Language
Content-Type
允许使用的值为:application/x-www-form-urlencoded
、multipart/form-data
或text/plain
上传文件用法
可以通过 HTML <input type="file" />
元素,FormData()
和 fetch()
上传文件。
const formData = new FormData();
const fileField = document.querySelector('input[type="file"]');
formData.append('username', 'abc123');
formData.append('avatar', fileField.files[0]);
fetch('https://example.com/profile/avatar', {
method: 'PUT',
body: formData
})
.then(response => response.json())
.then(result => {
console.log('Success:', result);
})
.catch(error => {
console.error('Error:', error);
});
以上,将获取到的文件数据组装到FormData
对象里,然后由请求的body带给服务端。
上传多个文件的用法
可以通过 HTML <input type="file" multiple />
元素,FormData()
和 fetch()
上传文件。
const formData = new FormData();
const photos = document.querySelector('input[type="file"][multiple]');
formData.append('title', 'My Vegas Vacation');
for (let i = 0; i < photos.files.length; i++) {
formData.append(`photos_${i}`, photos.files[i]);
}
fetch('https://example.com/posts', {
method: 'POST',
body: formData,
})
.then(response => response.json())
.then(result => {
console.log('Success:', result);
})
.catch(error => {
console.error('Error:', error);
});
多个文件的话,遍历组装进去即可。
Response对象
fetch()
请求成功以后,得到的是一个 Response
对象。它对应服务器的 HTTP 回应。
Response有以下属性:
body
一个 ReadableStream
,或者对于使用空的 body
属性构建的任意的 Response
对象,或没有任何主体的实际 HTTP 响应,则为 null
。
bodyUsed
一个只读属性。用以表示该 body 是否被使用过。
headers
包含与响应关联的Headers
对象。
ok
包含一个布尔值,表明响应是否成功(状态码在 200-299 范围内).
redirected
表明该响应是否为一个重定向的请求的结果。
status
包含响应的状态代码(例如,成功为 200)。
statusText
包含与状态代码相对应的状态消息(例如,对于 200 可以确定)。
type
包含一种响应的类型。可能值如下:
basic
:标准值,同源响应,暴露除了“Set-Cookie”之外的所有标头。cors
:从有效的跨源请求接收到响应。某些标头和主体可以被访问。error
:网络错误。没有有用的描述错误的信息。响应的状态为 0,header 为空且不可变。这是从Response.error()
中获得的响应的类型。opaque
:对跨源资源的“no-cors”请求的响应。严格限制。opaqueredirect
:fetch 请求是通过redirect: "manual"
发出的。响应的状态是 0,标头是空的,主体是 null,trailer 是空的。
url
返回请求的URL值,如果发生重定向,URL 属性的值将是在任何重定向之后获得的最终 URL。
Response对象读取的方法
arrayBuffer()
Response
上的方法 arrayBuffer()
接受一个 Response
流,并等待其读取完成。它返回一个 promise 实例,并 resolve 一个 ArrayBuffer
对象。
response.arrayBuffer().then(function(buffer) {
//
)};
function getData() {
source = audioCtx.createBufferSource();
var myRequest = new Request('viper.ogg');
fetch(myRequest).then(function(response) {
response.arrayBuffer().then(function(buffer) {
audioCtx.decodeAudioData(buffer, function(decodedData) {
source.buffer = decodedData;
source.connect(audioCtx.destination);
});
});
});
};
play.onclick = function() {
getData();
source.start(0);
play.setAttribute('disabled', 'disabled');
}
blob()
从Response读取到blob。
如下例子:
var myImage = document.querySelector('img');
var myRequest = new Request('flowers.jpg');
fetch(myRequest)
.then(function(response) {
return response.blob();
})
.then(function(myBlob) {
var objectURL = URL.createObjectURL(myBlob);
myImage.src = objectURL;
});
我们使用Request.Request构造方法创建了一个新的 request 对象,然后使用它来获取一个 JPG 文件。当 fetch 成功的时候,我们使用 blob() 从 response 中读取一个Blob对象,并使用URL.createObjectURL 将它放入一个 object URL,然后把 URL 设置为img元素的 src 属性以显示这张图片。
formData()
返回得到一个FormData对象。
response.formData()
主要用在 Service Worker 里面,拦截用户提交的表单,修改某些数据以后,再提交给服务器。
json()
Response
mixin 的 json()
方法接收一个 Response
流,并将其读取完成。它返回一个 Promise,Promise 的解析 resolve 结果是将文本体解析为 JSON
。
const myList = document.querySelector('ul');
const myRequest = new Request('products.json');
fetch(myRequest)
.then(response => response.json())
.then(data => {
for (const product of data.products) {
let listItem = document.createElement('li');
listItem.appendChild(
document.createElement('strong')
).textContent = product.Name;
listItem.append(
` can be found in ${
product.Location
}. Cost: `
);
listItem.appendChild(
document.createElement('strong')
).textContent = `£${product.Price}`;
myList.appendChild(listItem);
}
});
以上是我们使用 Request.Request
构造函数创建一个新的请求,然后使用它来获取一个 .json
文件。当获取成功时,我们使用 json()
读取并解析数据,然后像预期的那样从结果对象中读取值,并将其插入到列表项中以显示我们的产品数据。
text()
Response
mixin 的 text()
方法提供了一个可供读取的“返回流”(Response
stream),并将它读取完。它返回一个包含 USVString
对象(也就是文本)的 Promise 对象,返回结果的编码永远是 UTF-8。
例子如下:
const myArticle = document.querySelector('article');
const myLinks = document.querySelectorAll('ul a');
for(i = 0; i <= myLinks.length-1; i++) {
myLinks[i].onclick = function(e) {
e.preventDefault();
var linkData = e.target.getAttribute('data-page');
getData(linkData);
}
};
function getData(pageId) {
console.log(pageId);
const myRequest = new Request(pageId + '.txt');
fetch(myRequest).then(function(response) {
return response.text().then(function(text) {
myArticle.innerHTML = text;
});
});
}
我们使用 Request()
构造函数创建了一个请求(Request)对象,然后,使用它获取指定的.txt
的文件,当 fetch 函数执行成功,我们使用 text()
函数来返回一个USVString
(text) 对象,将它设置到 <article>
对象的innerHTML
(元素文本)中。
clon()
Response
接口的 clone()
方法创建一个响应对象的克隆,这个对象在所有方面都是相同的,但是储存在不同的变量中。
如下例子:
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;
});
});
我们使用 Request()
构造函数创建一个新的 Request
来传递一个 JPG 路径。然后我们使用 fetch()
获取这个请求。当 fetch 成功兑现时,我们克隆它,使用两个 Body.blob
调用从两个响应中提取 blob,使用 URL.createObjectURL
从 blob 创建对象 URL,并将它们显示在两个单独的 <img>
元素中。
总结
以上就是关于Fetch API的详细解析。