Fetch
Fetch API 提供了一个 JavaScript 接口,用于访问和操纵 HTTP 管道的一些具体部分,例如请求和响应。它还提供了一个全局 fetch() 方法,该方法提供了一种简单,合理的方式来跨网络异步获取资源。
一、概念
Fetch 提供了对 Request 和 Response 对象的通用定义。使之今后可以被使用到更多地应用场景中:无论是 service worker、Cache API、又或者是其他处理请求和响应的方式,甚至是任何一种需要你自己在程序中生成响应的方式。
它同时还为有关联性的概念,例如CORS和HTTP原生头信息,提供一种新的定义,取代它们原来那种分离的定义。
二、语法
Promise<Response> fetch(input[, init]);
1、参数
input
定义要获取的资源。这可能是:
- 一个
USVString字符串,包含要获取资源的URL。一些浏览器会接受blob:和data:作为schemes. - 一个
Request对象。
init 可选
一个配置项对象,包括所有对请求的设置。可选的参数有:
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 , 必须提供这个选项,也可以接受FederatedCredential实例或是一个PasswordCredential实例。cache: 请求的cache模式:default、no-store、reload、no-cache、force-cache或者only-if-cached。redirect: 可用的redirect模式:follow(自动重定向),error(如果产生重定向将自动终止并且抛出一个错误), 或者manual(手动处理重定向). 默认值是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=)。
2、返回值
一个 Promise,resolve 时回传 Response 对象。
三、Fetch和Ajax的不同
- 当接收到一个代表错误的
HTTP状态码时,从fetch()返回的Promise不会被标记为reject, 即使响应的HTTP状态码是 404 或 500。相反,它会将Promise状态标记为resolve(但是会将resolve的返回值的ok属性设置为false),仅当网络故障时或请求被阻止时,才会标记为reject。 fetch()可以接受跨域cookies;你也可以使用 fetch() 建立起跨域会话。fetch不会默认发送cookies。除非你使用了credentials的初始化选项。credentials 值为 same-origin。
四、请求示例
示例
fetch('https://api.github.com/users/chriscoyier/repos').then(res => {
console.log(res)
}).catch((e) => {
console.log(e)
})
打印的日志
body: ReadableStream
bodyUsed: true
headers: Headers {}
ok: true
redirected: false
status: 200
statusText: "OK"
type: "cors"
url: "https://api.github.com/users/chriscoyier/repos"
__proto__: Response
转化(Body mixin)
属性
Body.body
一个简单的getter用于暴露一个ReadableStream类型的主体内容。
Body.bodyUsed
一个Boolean 值指示是否body已经被标记读取。
方法
Body.arrayBuffer()
使Response挂起一个流操作并且在完成时读取其值,它返回一个Promise对象,其resolve参数类型是ArrayBuffer。此操作会将bodyUsed状态改为已使用(true)。
Body.blob()
使Response挂起一个流操作并且在完成时读取其值,它返回一个Promise对象,其resolve参数类型是Blob。此操作会将bodyUsed状态改为已使用(true)。
Body.formData()
使Response挂起一个流操作并且在完成时读取其值,它返回一个Promise对象,其resolve参数类型是FormData表单。此操作会将bodyUsed状态改为已使用(true)。
Body.json()
使Response挂起一个流操作并且在完成时读取其值,它返回一个Promise对象,其resolve参数类型是使用JSON解析body文本的结果。此操作会将bodyUsed状态改为已使用(true)。
Body.text()
使Response挂起一个流操作并且在完成时读取其值,它返回一个Promise对象,其resolve参数类型是USVString(文本)。此操作会将bodyUsed状态改为已使用(true)。
完整示例
fetch('https://api.github.com/users/chriscoyier/repos').then(res => {
console.log('res', res)
console.log('res.body', res.body)
console.log('res.bodyUsed', res.bodyUsed)
res.json().then(_res => {
console.log('res.bodyUsed', res.bodyUsed)
console.log('_res', _res)
}).catch(e => {
console.log(e)
})
}).catch((e) => {
console.log(e)
})
打印日志
'res'
body: (...)
bodyUsed: true
headers: Headers {}
ok: true
redirected: false
status: 200
statusText: "OK"
type: "cors"
url: "https://api.github.com/users/chriscoyier/repos"
'res.body' ReadableStream {locked: false}
'res.bodyUsed' false
'res.bodyUsed' true
//res.json()解析之后的值
'_res' (30) [{…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}]
async/await
(async () => {
let res = await fetch('https://api.github.com/users/chriscoyier/repos')
console.log(res)
})();
示例
1、携带cookie
credentials
为了让浏览器发送包含凭据的请求(即使是跨域源),要将credentials: 'include'添加到传递给 fetch()方法的init对象。
fetch(url, {
credentials: 'include'
})
如果你只想在请求URL与调用脚本位于同一起源处时发送凭据,请添加 credentials: 'same-origin'。
要改为确保浏览器不在请求中包含凭据,请使用 credentials: 'omit'。
fetch(url, {
credentials: 'same-origin' //credentials: 'omit'
})
2、上传JSON数据
'Content-Type': 'application/json'
let url = 'https://xxx';
let data = { username: 'example' };
fetch(url, {
method: 'POST',
body: JSON.stringify(data),
headers: new Headers({
'Content-Type': 'application/json'
})
}).then(res => res.json())
.catch(error => console.error('Error:', error));
3、上传文件
FormData()
let formData = new FormData();
let fileField = document.querySelector("input[type='file']");
formData.append('name', 'abc123');
formData.append('pic', fileField.files[0]);
fetch(url, {
method: 'PUT',
body: formData
})
.then(response => response.json())
.catch(error => console.error('Error:', error));
4、上传多个文件
<input type="file" mutiple/>
let formData = new FormData();
let photos = document.querySelector("input[type='file'][multiple]");
formData.append('title', 'My Vegas Vacation');
// formData 只接受文件、Blob 或字符串,不能直接传递数组,所以必须循环嵌入
for (let i = 0; i < photos.files.length; i++) {
formData.append('photo', photos.files[i]);
}
fetch(url, {
method: 'POST',
body: formData
})
.then(response => response.json())
.then(response => console.log('Success:', JSON.stringify(response)));
5、自定义请求对象
除了传给 fetch() 一个资源的地址,你还可以通过使用 Request() 构造函数来创建一个 request 对象,然后再作为参数传给 fetch():
let myHeaders = new Headers();
let myInit = {
method: 'GET',
headers: myHeaders,
mode: 'cors',
cache: 'default'
};
let myRequest = new Request('flowers.jpg', myInit);
fetch(myRequest).then((response) => {
}).then((myBlob) => {});
Request() 和 fetch() 接受同样的参数。你甚至可以传入一个已存在的 request 对象来创造一个拷贝:
var anotherRequest = new Request(myRequest,myInit);
五、Headers
可以通过 Headers() 构造函数来创建一个你自己的headers 对象。一个 headers 对象是一个简单的多名值对。
let content = "Hello World";
let myHeaders = new Headers();
myHeaders.append("Content-Type", "text/plain");
myHeaders.append("Content-Length", content.length.toString());
myHeaders.append("X-Custom-Header", "ProcessThisImmediately");
也可以传一个多维数组或者对象字面量:
myHeaders = new Headers({
"Content-Type": "text/plain",
"Content-Length": content.length.toString(),
"X-Custom-Header": "ProcessThisImmediately",
});
Guard属性
由于 Headers 可以在 request 请求中被发送或者在 response 请求中被接收,并且规定了哪些参数是可写的,Headers 对象有一个特殊的 guard 属性。这个属性没有暴露给 Web,但是它影响到哪些内容可以在 Headers 对象中被操作。
none:默认的request:从 request 中获得的 headers(Request.headers)只读request-no-cors:从不同域(Request.mode no-cors)的request 中获得的 headers 只读response:从 response 中获得的 headers(Response.headers)只读immutable:在 ServiceWorkers 中最常用的,所有的 headers 都只读。
六、Response 对象
Response 实例是在 fetch() 处理完 promise 之后返回的。
属性
-
Response.headers只读 包含此 Response 所关联的 Headers 对象。 -
Response.ok只读 包含了一个布尔值,标示该 Response 成功(HTTP 状态码的范围在 200-299)。 -
Response.redirected只读 表示该 Response 是否来自一个重定向,如果是的话,它的 URL 列表将会有多个条目。 -
Response.status只读 包含 Response 的状态码 (例如 200 表示成功)。 -
Response.statusText只读 包含了与该 Response 状态码一致的状态信息(例如,OK对应 200)。 -
Response.type只读 包含 Response 的类型(例如,basic、cors)。 -
Response.url只读 包含 Response 的URL。 -
Response.useFinalURL包含了一个布尔值,来标示这是否是该 Response 的最终 URL。 Response 实现了 Body 接口,所以以下属性亦可用: -
Body.body只读 一个简单的 getter,用于暴露一个 ReadableStream 类型的 body 内容。 -
Body.bodyUsed只读 包含了一个布尔值来标示该 Response 是否读取过 Body。
方法
Response.clone()创建一个 Response 对象的克隆。Response.error()返回一个绑定了网络错误的新的 Response 对象。Response.redirect()用另一个 URL 创建一个新的 Response。Response实现了 Body 接口,所以Body的方法都可以用