跟我一起探索 HTTP-Fetch API

69 阅读5分钟

Fetch API

Fetch API 提供了一个获取资源的接口(包括跨网络通信)。对于任何使用过 XMLHttpRequest 的人都能轻松上手,而且新的 API 提供了更强大和灵活的功能集。

备注: 此特性在 Web Worker中可用

Fetch API is new old version of AJAX | Diogo Rodrigues

概念和用法

Fetch 提供了对 RequestResponse(以及其他与网络请求有关的)对象的通用定义。这将在未来更多需要它们的地方使用它们,无论是 service worker、Cache API,又或者是其他处理请求和响应的方式,甚至是任何一种需要你自己在程序中生成响应的方式(即使用计算机程序或者个人编程指令)。

它同时还为有关联性的概念,例如 CORSHTTP Origin 标头信息,提供一种新的定义,取代它们原来那种分离的定义。

发送请求或者获取资源,请使用 fetch() 方法。它在很多接口中都被实现了,更具体地说,是在 WindowWorkerGlobalScope 接口上。因此在几乎所有环境中都可以用这个方法获取资源。

fetch() 强制接受一个参数,即要获取的资源的路径。它返回一个 Promise,该 Promise 会在服务器使用标头响应后,兑现为该请求的 Response——即使服务器的响应是 HTTP 错误状态。你也可以传一个可选的第二个参数 init

一旦 Response 被返回,有许多方法可以获取主体定义的内容以及如何处理它。

你也可以通过 Request()Response() 构造函数直接创建请求和响应。但是我们不建议这么做,它们更可能被创建为其他的 API 操作的结果(比如,service worker 中的 FetchEvent.respondWith

与 jQuery 的区别

fetch 规范主要在三个方面与 jQuery.ajax() 不同:

  • fetch() 返回的 Promise 不会因 HTTP 的错误状态而被拒绝,即使响应是 HTTP 404500。相反,它将正常兑现(ok 状态会被设置为 false),并且只有在网络故障或者有任何阻止请求完成时,才拒绝。

  • 除非你在init 对象中设置(去包含)credentials,否则fetch()将不会发送跨源 cookie

备注: 更多关于 Fetch API 的用法,参考使用 Fetch,以及一些概念 Fetch 基础概念

中止 fetch

要中止未完成的 fetch(),甚至 XMLHttpRequest 操作,请使用 AbortControllerAbortSignal 接口。

Fetch 接口

  • fetch() 包含了 fetch() 方法,用于获取资源。

  • Headers 表示响应/请求的标头信息,允许你查询它们,或者针对不同的结果做不同的操作。

  • Request 相当于一个资源请求。

  • Response 相当于请求的响应

fetch()

全局的 fetch() 方法用于发起获取资源的请求。它返回一个 promise,这个 promise 会在请求响应后被 resolve,并传回 Response 对象。

[Window] 和 [WorkerGlobalScope] 都实现了 WorkerOrGlobalScope。 ——这意味着基本在任何场景下只要你想获取资源,都可以使用位于 WorkerOrGlobalScope 中的 fetch() 方法。

当遇到网络错误时,fetch() 返回的 promise 会被 reject,并传回 TypeError,虽然这也可能因为权限或其他问题导致。成功的 fetch() 检查不仅要包括 promise 被 resolve,还要包括 Response.ok 属性为 true。HTTP 404 状态并不被认为是网络错误。

fetch() 方法由 Content Security Policyconnect-src指令控制,而不是它请求的资源。

备注: fetch() 方法的参数与 Request() 构造器是一样的。

语法

Promise<Response> fetch(input[, init]);

参数

  • ?input

    定义要获取的资源。这可能是:一个 USVString 字符串,包含要获取资源的 URL。一些浏览器会接受 blob:data: 作为 schemes.一个 Request 对象。

  • init 可选

    一个配置项对象,包括所有对请求的设置。可选的参数有:

    • method: 请求使用的方法,如 GETPOST
    • headers: 请求的头信息,形式为 Headers 的对象或包含 ByteString 值的对象字面量。
    • body: 请求的 body 信息:可能是一个 BlobBufferSourceFormDataURLSearchParams 或者 USVString 对象。注意 GET 或 HEAD 方法的请求不能包含 body 信息。
    • mode: 请求的模式,如 corsno-cors 或者 same-origincredentials: 请求的 credentials,如 omitsame-origin 或者 include。为了在当前域名内自动发送 cookie,必须提供这个选项,从 Chrome 50 开始,这个属性也可以接受 FederatedCredential (en-US) 实例或是一个 PasswordCredential (en-US) 实例。
    • cache: 请求的 cache 模式:defaultno-storereloadno-cacheforce-cache 或者 only-if-cachedredirect: 可用的 redirect 模式:follow (自动重定向), error (如果产生重定向将自动终止并且抛出一个错误),或者 manual (手动处理重定向)。在 Chrome 中默认使用 follow(Chrome 47 之前的默认值是 manual)。
    • referrer: 一个 USVString 可以是 no-referrerclient 或一个 URL。默认是 client
    • referrerPolicy: 指定了 HTTP 头部 referer 字段的值。可能为以下值之一:no-referrerno-referrer-when-downgradeoriginorigin-when-cross-originunsafe-url
    • integrity: 包括请求的 subresource integrity 值(例如: sha256-BpfBw7ivV8q2jLiT13fxDYAe2tJllusRSZ273h2nFSE=)。

返回值

一个 Promiseresolve 时回传 Response 对象。

例外

类型描述
AbortError请求被AbortController.abort()终止。
TypeError从Firefox 43开始,如果fetch()接收到含有用户名和密码的 URL(例如http://user:password@example.com),它将会抛出一个TypeError

示例

Fetch Request 示例中,我们使用对应的构造器创建了一个新的 Request 对象,然后调用 fetch() 方法获取资源。因为我们是在请求一个图片,为了解析正常,我们对响应执行 [Body.blob] 来设置相应的 MIME 类型。然后创建一个 Object URL,并元素中把它显示出来。

var myImage = document.querySelector('img');

var myRequest = new Request('flowers.jpg');

fetch(myRequest).then(function(response) {
  return response.blob();
}).then(function(response) {
  var objectURL = URL.createObjectURL(response);
  myImage.src = objectURL;
});

在Fetch with init then Request 示例中,我们做同样的操作,除了在调用 fetch() 时传入一个 init 对象:

var myImage = document.querySelector('img');

var myHeaders = new Headers();
myHeaders.append('Content-Type', 'image/jpeg');

var myInit = { method: 'GET',
               headers: myHeaders,
               mode: 'cors',
               cache: 'default' };

var myRequest = new Request('flowers.jpg');

fetch(myRequest,myInit).then(function(response) {
  ...
});

你也可以传入同样的 init 对象到 Request 构造器,来实现同样的效果,如:

var myRequest = new Request('flowers.jpg',myInit);

init 对象中的 headers 也可以是一个对象字面量:

var myInit = { method: 'GET',
               headers: {
                   'Content-Type': 'image/jpeg'
               },
               mode: 'cors',
               cache: 'default' };

var myRequest = new Request('flowers.jpg', myInit);