介绍
Fetch
是基于Promise
开发的用于访问和操纵 HTTP 管道的一个API
。其提供了一个全局 fetch()
方法,该方法提供了一种简单,合理的方式来跨网络异步获取资源。
以前浏览器中的网络请求只能通过XMLHttpRequest
实现(虽然大多使用的是封装过后的接口)。而Fetch
则结合Promise
提供了一种更加简化的发送网络请求的方式(其调用方法与axiso
相似)。
用法
Fetch()
方法
Fetch
接受两个参数:
Promise<Response> fetch(input[, init]);
?input
定义要获取的资源。这可能是:一个
USVString
字符串,包含要获取资源的 URL。一些浏览器会接受blob:
和data:
作为 schemes.一个Request
对象。init 可选
一个配置项对象,包括所有对请求的设置。可选的参数有:
method
: 请求使用的方法,如GET、POST。
headers
: 请求的头信息,形式为Headers
值的对象字面量。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](https://developer.mozilla.org/zh-CN/docs/Web/API/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=)。
返回值
一个 Promise
对象。
例子
发送带凭据的请求
注意:Fetch
默认是不携带凭据的请求(即使是跨域源),要将credentials: 'include'
添加到传递给 fetch()
方法的init
对象,才能使请求携带凭证。
1 | fetch('https://example.com', { |
如果你只想在请求URL与调用脚本位于同一起源处时发送凭据,请添加 credentials: 'same-origin'
。
1 | // The calling script is on the origin 'https://example.com' |
上传 JSON 数据
使用 fetch()
POST JSON数据
1 | var url = 'https://example.com/profile'; |
上传文件
可以通过 HTML <input type="file" />
元素,FormData()
和 fetch()
上传文件。
1 | var formData = new FormData(); |
上传多个文件
可以通过HTML <input type="file" mutiple/>
元素,FormData()
和 fetch()
上传多个文件。
1 | var formData = new FormData(); |
自定义请求对象
除了传给 fetch()
一个资源的地址,你还可以通过使用 Request()
构造函数来创建一个 request 对象,然后再作为参数传给 fetch()
:
1 | var myHeaders = new Headers(); |
Request()
和 fetch()
接受同样的参数。你甚至可以传入一个已存在的 request 对象来创造一个拷贝:
1 | var anotherRequest = new Request(myRequest,myInit); |
Request
对象
Request
构造器可以构造一个Request
对象,其作为Fetch
方法的参数。
该构造器接受的参数与Fetch
一致:
- 请求地址
init
对象
此处不再赘述。
此外,我们可直接通过const method = Request.method
的方式来获取init
属性。如:
1 | const myRequest = new Request('http://localhost/flowers.jpg'); |
方法
Request
对象有以下方法可以调用:
Request.clone()
创建当前request的副本。
Request
实现 Body`, 因此它也有以下方法可用:
Body.arrayBuffer()
返回解决一个
ArrayBuffer
表示的请求主体的promise.Body.blob()
返回解决一个
Blob
表示的请求主体的promise.Body.formData()
返回解决一个
FormData
表示的请求主体的promise.Body.json()
返回解决一个
JSON
表示的请求主体的promise.Body.text()
返回解决一个
USVString
(文本)表示的请求主体的promise.
注意:这些Body功能只能运行一次; 随后的调用将通过空strings/ ArrayBuffers
解析.
header
对象
使用 Headers
的接口,你可以通过 Headers()
构造函数来创建一个你自己的 headers 对象。一个 headers 对象是一个简单的多名值对:
1 | let content = "Hello World"; |
也可以直接接受一个字面量对象来构造header
对象
1 | myHeaders = new Headers({ |
方法
Headers.append()
给现有的header添加一个值, 或者添加一个未存在的header并赋值.
Headers.delete()
从Headers对象中删除指定header.
Headers.entries()
以
迭代器
的形式返回Headers对象中所有的键值对.Headers.get()
以
ByteString
的形式从Headers对象中返回指定header的全部值.Headers.has()
以布尔值的形式从Headers对象中返回是否存在指定的header.
Headers.keys()
以
迭代器
的形式返回Headers对象中所有存在的header名.Headers.set()
替换现有的header的值, 或者添加一个未存在的header并赋值.
Headers.values()
以
迭代器
的形式返回Headers对象中所有存在的header的值.
注意
- 在header已存在或者有多个值的状态下
Headers.set()
和Headers.append()
的使用有如下区别,Headers.set()
将会用新的值覆盖已存在的值, 但是Headers.append()
会将新的值添加到已存在的值的队列末尾. - 如果您尝试传入名称不是有效的HTTP头名称的引用,则所有Headers方法都将引发
TypeError
。 如果头部有一个不变的Guard,则变异操作将会抛出一个TypeError
。 在其他任何失败的情况下,他们默默地失败。 - 出于安全考虑,某些头只能由用户代理控制。这些头信息包括 forbidden header names 和 forbidden response header names。
- 一个Headers对象也有一个关联的guard,它具有不可变的值,
request
,request-no-cors
,response
或none
。 这会影响 set(),
delete(), 和
append()`方法 改变header.
Guard属性
描述
Guard 是 Headers
对象的特性,基于不同的情况,它可以有以下取值:immutable、request、request-no-cors、response 或 none。
由于 Headers 可以在 request 请求中被发送或者在 response 请求中被接收,并且规定了哪些参数是可写的,Headers 对象中的 guard 属性。这个属性没有暴露给 Web,但是它影响到哪些内容可以在 Headers 对象中被操作。
规则
当使用 Headers()constructor
创建一个新的 Headers
对象的时候,它的 guard 被设置成 none(默认值)
。当创建 Request
或 Response
对象的时候,它将拥有一个按照以下规则实现的与之关联的 Headers`对象:
新对象的类型 | 创建时的构造函数 | 关联的 Headers 对象的 guard |
---|---|---|
Request |
Request() |
request |
Request |
Request(),mode 设置成 no-cors | request-no-cors |
Response |
Response() |
response |
Response |
immutable |
immutable |
guard
属性值的特征:
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
对象,但更多的是通过一个Fetch
请求返回的Response
对象。
属性
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.arrayBuffer()
读取
Response
对象并且将它设置为已读(因为 Responses 对象被设置为了 stream 的方式,所以它们只能被读取一次),并返回一个被解析为ArrayBuffer
格式的 Promise 对象。Body.blob()
读取
Response
对象并且将它设置为已读(因为 Responses 对象被设置为了 stream 的方式,所以它们只能被读取一次),并返回一个被解析为Blob
格式的 Promise 对象。Body.formData()
读取
Response
对象并且将它设置为已读(因为 Responses 对象被设置为了 stream 的方式,所以它们只能被读取一次),并返回一个被解析为FormData
格式的 Promise 对象。Body.json()
读取
Response
对象并且将它设置为已读(因为 Responses 对象被设置为了 stream 的方式,所以它们只能被读取一次),并返回一个被解析为JSON
格式的 Promise 对象。Body.text()
读取
Response
对象并且将它设置为已读(因为 Responses 对象被设置为了 stream 的方式,所以它们只能被读取一次),并返回一个被解析为USVString
格式的 Promise 对象。
body
对象
**Body
**代表响应/请求的正文,允许你声明其内容类型是什么以及应该如何处理。
一般我们也是从一个请求中得到一个body
对象。当然,直接通过body
构造器来创建一个body
也是被允许的。
属性
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)。
比起XHR
来,这些方法让非文本化的数据使用起来更加简单。
兼容性
可以看到Fetch
的兼容性还是有一定的问题,Chrome
42版本才开始支持从与Firefox
从39版本才支持,而IE到目前位置都不支持。这是一个很大的问题。如果要在生产环境中使用,必须引入很多pollyfill
,相较于使用Promise
封装的XHR
,这样看来优势又荡然无存,随着版本的迭代,未来肯定是Fetch
的,但不是现在。