前言
目前我们大多数用到的网络请求方式就是使用 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 请求头:
AcceptAccept-LanguageContent-LanguageContent-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的详细解析。