fetch-api简介
在抱怨自己赚钱之少之前先努力学着让自己值钱。十多年来,我们一直使用 XMLHttpRequest(XHR)来发送异步请求,XHR 很实用,但并不是一个设计优良的 API,在设计上并不符合职责分离原则,输入、输出以及状态都杂糅在同一对象中,并用事件机制来跟踪状态变化。并且,基于事件的模型与最近流行的 Promise 和 generator 异步编程模型不太友好。
Fetch API 旨在修正上述缺陷,它提供了与 HTTP 语义相同的 JS 语法,简单来说,它引入了 fetch() 这个实用的方法来获取网络资源。
在 Fetch 规范中对 API 进行了定义,它结合 ServiceWorkers,尝试做到如下优化:
- 改善离线体验
- 保持可扩展性
简单示例
Fetch API 中最常用的是 fetch() 方法,该方法最简单的形式是,接受一个 URL 参数并返回以一个 promise 对象:
1 | fetch("/data.json").then(function(res) { |
如果是提交一个POST请求,代码如下:
1 | fetch("http://www.example.org/submit.php", { |
fetch() 方法的参数和 Request() 构造函数的参数完全一致,所以你可以传任意复杂的参数来实现更强大的 fetch(),下面将详细介绍。
Headers
Fetch 引入了 3 个接口,分别是 Headers,Request 和 Response。他们直接对应于的 HTTP 中相应的概念,但是基于隐私和安全考虑,也有些区别,例如支持 CORS 规则以及保证 cookies 不能被第三方获取。
Headers 接口是一个简单的键值对:
1 | ar content = "Hello World"; |
也可以给构造函数传一个多维数组或 JS 字面量对象:
1 | reqHeaders = new Headers({ |
Headers 的内容可被检索:
1 | console.log(reqHeaders.has("Content-Type")); // true |
一些操作只在 ServiceWorkers 中可用,但这些 API 使得操作 header 更为方便。
由于 header 可以在发送请求时被发送或在收到响应时被接收,并规定了那些参数可写,所以在 Headers 对象中有个一 guard 属性,来指定哪些参数可以被改变。
可能的值如下:
- “none”:默认值
- “request”:Request.headers 对象只读
- “request-no-cors”:在 no-cors 模式下,Request.headers 对象只读
- “response”:Response.headers 对象只读
- “immutable”:通常在 ServiceWorkers 中使用,所有 Header 对象都为只读
在规范中对每个 guard 属性值有更详细的描述。例如,当 guard 为 request 时,你将不能添加或修改header 的 Content-Length 属性。
如果使用了一个不合法的 HTTP Header 名,那么 Headers 的方法通常都抛出 TypeError 异常。如果不小心写入了一个只读属性,也会抛出一个 TypeError 异常。除此以外,失败了将不抛出任何异常。例如:
1 | var res = Response.error(); |
Request
通过构造一个 Request 对象来获取网络资源,构造函数需要 URL、method 和 headers 参数,同时也可以提供请求体(body)、请求模式(mode)、credentials 和 cache hints 等参数。
最简单的形式如下:
1 | var req = new Request("/index.html"); |
也可以将一个 Request 对象传给构造函数,这将返回该对象的一个副本(这与 clone() 方法不同,后面将介绍)。
1 | var copy = new Request(req); |
同时,这种形式通常只在 ServiceWorkers 中使用。
除 URL 之外的参数只能通过第二个参数传递,该参数是一个键值对:
1 | var uploadReq = new Request("/uploadImage", { |
mode 参数用来决定是否允许跨域请求,以及哪些 response 属性可读。可选的 mode 值为 “same-origin”、”no-cors”(默认)以及 “cors”。
same-origin
该模式很简单,如果一个请求是跨域的,那么将返回一个 error,这样确保所有的请求遵守同源策略。
1 | var arbitraryUrl = document.getElementById("url-input").value; |
Response
Response 对象通常在 fetch() 的回调中获得,也可以通过 JS 构造,不过这通常只在 ServiceWorkers 中使用。
Response 对象中最常见的属性是 status(整数,默认值是 200)和statusText(默认值是 “OK”)。还有一个 ok 属性,这是 status 值为 200~299
时的语法糖。
另外,还有一个 type 属性,它的值可能是 “basic”、”cors”、”default”、”error” 或 “opaque”。
- “basic”:同域的响应,除 Set-Cookie 和 Set-Cookie2 之外的所有 Header 可用
- “cors”:Response 从一个合法的跨域请求获得,某些 Header 和 body 可读
- “error”:网络错误。Response 对象的 status 属性为 0,headers 属性为空并且不可写。当 Response 对象从 Response.error() 中得到时,就是这种类型
- “opaque”:在 “no-cors” 模式下请求了跨域资源。依靠服务端来做限制
当 type 属性值为 “error” 时会导致 fetch() 方法的 Promise 被 reject,reject 回调的参数为 TypeError 对象。
还有一些属性只在 ServerWorker 下有效。在 ServerWorker 下返回一个 Response 的正确方式为:
1 | addEventListener('fetch', function(event) { |
如你所见,Response 构造函数接收两个参数:返回的 body 和一个键值对对象,通过该对象来设置 status、statusText 和 headers 属性。
静态方法 Response.error() 将返回一个错误响应,Response.redirect(url, status) 将返回一个跳转响应。
http://bubkoo.com/2015/05/08/introduction-to-fetch/
https://developer.mozilla.org/zh-CN/docs/Web/API/Fetch_API/Using_Fetch