fetch() 简介

Matt Gaunt

借助 fetch(),您可以发出类似于 XMLHttpRequest (XHR) 的网络请求。主要区别在于,Fetch API 使用 Promise,其 API 更简单,可帮助您避免 XMLHttpRequest API 中复杂的回调。

浏览器支持

  • Chrome:42.
  • Edge:14.
  • Firefox:39.
  • Safari:10.1。

来源

如果您以前从未使用过Promise,请参阅 JavaScript Promise 简介

基本提取请求

下面是一个先使用 XMLHttpRequest 然后使用 fetch 实现的示例。我们希望请求某个网址、获取响应,并将其解析为 JSON。

XMLHttpRequest

XMLHttpRequest 需要两个监听器来处理成功和错误情况,以及对 open()send() 的调用。MDN 文档中的示例

function reqListener () {
  const data = JSON.parse(this.responseText);
  console.log(data);
}

function reqError (err) {
  console.log('Fetch Error :-S', err);
}

const oReq = new XMLHttpRequest();
oReq.onload = reqListener;
oReq.onerror = reqError;
oReq.open('get', './api/some.json', true);
oReq.send();

抓取

我们的提取请求如下所示:

fetch('./api/some.json')
  .then(response => {
    if (response.status !== 200) {
      console.log(`Looks like there was a problem. Status Code: ${response.status}`);

      return;
    }

    // Examine the text in the response
    response.json().then(function(data) {
      console.log(data);
    });
  })
  .catch(err => {
    console.log('Fetch Error :-S', err);
  });

fetch() 请求只需一次调用即可执行与 XHR 示例相同的工作。为了处理响应,我们首先检查响应状态是否为 200,然后将响应解析为 JSON。对 fetch() 请求的响应是一个 Stream 对象,这意味着在调用 json() 方法后,系统会返回一个 Promise。数据流是异步进行的。

响应元数据

前面的示例展示了 Response 对象的状态,以及如何将响应解析为 JSON。下面介绍了如何处理您可能需要访问的其他元数据,例如标头:

fetch('users.json').then(response => {
  console.log(response.headers.get('Content-Type'));
  console.log(response.headers.get('Date'));

  console.log(response.status);
  console.log(response.statusText);
  console.log(response.type);
  console.log(response.url);
});

响应类型

发出提取请求时,系统会为响应分配 response.type,值为“basic”“cors”或“opaque”。这些 types 显示资源的来源,您可以使用它们来确定如何处理响应对象。

当浏览器请求同一源的资源时,响应会采用 basic 类型,并且会限制您可以从响应中查看的内容。

如果针对其他来源的资源发出请求,并且该来源返回 CORS 标头,则类型为 corscors 响应与 basic 响应类似,但会将您可以查看的标头限制为 Cache-ControlContent-LanguageContent-TypeExpiresLast-ModifiedPragma

opaque 响应来自不返回 CORS 标头的其他来源。如果响应不透明,我们将无法读取返回的数据或查看请求的状态,这意味着您无法检查请求是否成功。

您可以为提取请求定义模式,以便仅解析特定类型的请求。您可以设置的模式如下:

  • same-origin 仅针对同一来源的资源请求才会成功,并会拒绝所有其他请求。
  • cors 允许对同一来源和返回适当 CORS 标头的其他来源的资源发出请求。
  • cors-with-forced-preflight 会在发出任何请求之前执行预处理检查
  • no-cors 旨在向不含 CORS 标头的其他来源发出请求,并生成 opaque 响应,但正如前所述,目前无法在窗口全局范围内执行此操作。

如需定义模式,请在 fetch 请求中将 options 对象添加为第二个参数,并在该对象中定义模式:

fetch('http://some-site.com/cors-enabled/some.json', {mode: 'cors'})
  .then(response => response.text())
  .then(text => {
    console.log('Request successful', text);
  })
  .catch(error => {
    log('Request failed', error)
  });

Promise 串联

Promise 的一项强大功能是能够将它们串联起来。对于 fetch(),这让您可以在提取请求之间共享逻辑。

如果您使用的是 JSON API,则需要检查状态并解析每个响应的 JSON。您可以通过在返回 Promise 的单独函数中定义状态和 JSON 解析,并使用提取请求仅处理最终数据和错误情况,从而简化代码。

function status (response) {
  if (response.status >= 200 && response.status < 300) {
    return Promise.resolve(response)
  } else {
    return Promise.reject(new Error(response.statusText))
  }
}

function json (response) {
  return response.json()
}

fetch('users.json')
  .then(status)
  .then(json)
  .then(data => {
    console.log('Request succeeded with JSON response', data);
  }).catch(error => {
    console.log('Request failed', error);
  });

此示例定义了一个 status 函数,用于检查 response.status,并返回已解析的 promise(以 Promise.resolve() 的形式)或已拒绝的 promise(以 Promise.reject() 的形式)。这是 fetch() 链中第一个被调用的方法。

如果 promise 解析完毕,脚本会调用 json() 方法,该方法会从 response.json() 调用返回第二个 promise,并创建一个包含解析的 JSON 的对象。如果解析失败,Promise 将被拒绝,并且 catch 语句会执行。

借助这种结构,您可以在所有提取请求中共享逻辑,从而更轻松地维护、阅读和测试代码。

POST 请求

有时,Web 应用需要使用 POST 方法调用 API,并在请求正文中添加一些参数。为此,请在 fetch() 选项中设置 methodbody 参数:

fetch(url, {
    method: 'post',
    headers: {
      "Content-type": "application/x-www-form-urlencoded; charset=UTF-8"
    },
    body: 'foo=bar&lorem=ipsum'
  })
  .then(json)
  .then(data => {
    console.log('Request succeeded with JSON response', data);
  })
  .catch(error => {
    console.log('Request failed', error);
  });

通过提取请求发送凭据

如需使用 Cookie 等凭据发出提取请求,请将请求的 credentials 值设置为 "include"

fetch(url, {
  credentials: 'include'
})