fetch请求

233 阅读4分钟

一、什么是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 Policy (en-US) 的 connect-src指令控制,而不是它请求的资源。

二、如何使用fetch?

1、fetch语法,包含input和options两个参数:

Promise<Response> fetch(input, options]);

2、fetch参数:

fetch方法可以接收两个参数 inputoptions

  • input 参数可以是字符串,包含要获取资源的 URL。也可以是一个 Request 对象。
  • options 是一个可选参数。一个配置项对象,包括所有对请求的设置。

options可选配置有:

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

三、常用的fetch请求

1、返回HTML

fetch('/users.html')
  .then(function(response) {
    return response.text()
  })
  .then(function(body) {
    document.body.innerHTML = body
  })
  .catch((err) => {})

2、返回JSON

fetch('/users.json')
  .then(function(response) {
    return response.json()
  })
  .then(function(json) {
    console.log('parsed json', json)
  })
  .catch(function(ex) {
    console.log('parsing failed', ex)
  })

3、元数据

fetch('/users.json')
.then(function(response) {
  console.log(response.headers.get('Content-Type'))
  console.log(response.headers.get('Date'))
  console.log(response.status)
  console.log(response.statusText)
})

4、表单请求

var form = document.querySelector('form')
fetch('/users', {
  method: 'POST',
  body: new FormData(form)
})

5、JSON请求

fetch('/users', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    name: 'Hubot',
    login: 'hubot',
  })
})

6、文件上传

var input = document.querySelector('input[type="file"]')
var data = new FormData()
data.append('file', input.files[0])
data.append('user', 'hubot')

fetch('/avatars', {
  method: 'POST',
  body: data
})

四、取消请求

fetch自身并没有提供中止请求的方法,如果需要取消请求需借助AbortControllerAbortSignal,目前有些浏览器已经实现了AbortController和AbortSignal,此时,我们可以通过AbortController中止fetch请求。

image.png

image.png

如上面截图,如果fetch设置了signal,然后可以执行 controller.abort() 方法终止请求,假设浏览器不支持AbortController和AbortSignal,但我们又想终止请求,我们该怎么办?此时,我们可以借助yet-another-abortcontroller-polyfill来实现,具体参考如下:

import 'yet-another-abortcontroller-polyfill'
import {fetch} from 'whatwg-fetch'

// use native browser implementation if it supports aborting
const abortableFetch = ('signal' in new Request('')) ? window.fetch : fetch

const controller = new AbortController()

abortableFetch('/avatars', {
  signal: controller.signal
}).catch(function(ex) {
  if (ex.name === 'AbortError') {
    console.log('request aborted')
  }
})

// some time later...
controller.abort()

五、拓展:

在整理fetch的过程中,发现了几个之前没注意到的构造函数,可以用作接口的请求和响应:

1、 Headers

其中Headers可以是多个键值对,使用如下:

const content = 'Hello World';
const myHeaders = new Headers();
myHeaders.append('Content-Type', 'text/plain');
myHeaders.append('Content-Length', content.length.toString());
myHeaders.append('X-Custom-Header', 'ProcessThisImmediately');

或者是一个对象:

const myHeaders = new Headers({
  'Content-Type': 'text/plain',
  'Content-Length': content.length.toString(),
  'X-Custom-Header': 'ProcessThisImmediately'
});

guard

由于 Headers 可以在 request 中被发送或者在 response 中被接收,并且规定了哪些参数是可写的,Headers 对象有一个特殊的 guard 属性。这个属性没有暴露给 Web,但是它影响到哪些内容可以在 Headers 对象中被操作。 可能的值如下:

  1. none:默认的。
  2. request:从 request 中获得的 headers(Request.headers)只读。
  3. request-no-cors:从不同域(Request.mode no-cors)的 request 中获得的 headers 只读。
  4. response:从 response 中获得的 headers(Response.headers)只读。
  5. immutable:在 ServiceWorkers 中最常用的,所有的 headers 都只读。

2、 Request

综合headers和requests的使用如下:

const myHeaders = new Headers();

const myRequest = new Request('flowers.jpg', {
  method: 'GET',
  headers: myHeaders,
  mode: 'cors',
  cache: 'default',
});

fetch(myRequest)
  .then(response => response.blob())
  .then(myBlob => {
    myImage.src = URL.createObjectURL(myBlob);
  });

其中,requests的语法如下,包含input和options两个参数:

var myRequest = new Request(input, options);

input:

其值可以是下面两者之一:

  • 一个直接包含你希望 fetch 的资源的 URL 的 USVString

  • 一个 Request 对象。请注意以下行为更新,以在保留安全性的同时使构造函数不太可能引发异常:

    -   如果此对象存在于构造函数调用的另一个起源上,则将除去[`Request.referrer` (en-US)](https://developer.mozilla.org/en-US/docs/Web/API/Request/referrer "Currently only available in English (US)")。
    -   如果此对象的导航为 [`Request.mode`](https://developer.mozilla.org/zh-CN/docs/Web/API/Request/mode),则`mode`将转换为`same-origin`
    

options:

一个可选对象,包含希望被包括到请求中的各种自定义选项。可用的选项如下:

  1. method: 请求的方法,例如:GETPOST
  2. headers: 任何你想加到请求中的头,其被放在Headers对象或内部值为ByteString 的对象字面量中。
  3. body: 任何你想加到请求中的 body,可以是BlobBufferSourceFormDataURLSearchParamsUSVString,或ReadableStream对象。注意GET 和 HEAD 请求没有 body。
  4. mode: 请求的模式,比如 corsno-corssame-origin, 或 navigate。默认值为 cors
  5. credentials: 想要在请求中使用的 credentials:: omitsame-origin, 或 include。默认值应该为omit。但在 Chrome 中,Chrome 47 之前的版本默认值为 same-origin ,自 Chrome 47 起,默认值为 include
  6. cache: 请求中想要使用的 cache mode
  7. redirect: 对重定向处理的模式: followerror, or manual。在 Chrome 中,Chrome 47 之前的版本默认值为 manual,自 Chrome 47 起,默认值为 follow
  8. referrer: 一个指定了no-referrerclient, 或一个 URL 的 USVString 。默认值是about:client
  9. integrity: 包括请求的 subresource integrity 值 (e.g., sha256-BpfBw7ivV8q2jLiT13fxDYAe2tJllusRSZ273h2nFSE=).

3、 Response response的使用大致如下:

const myBody = new Blob();

addEventListener('fetch', event => {
  // ServiceWorker intercepting a fetch
  event.respondWith(
    new Response(myBody, {
      headers: { 'Content-Type': 'text/plain' }
    })
  );
});

相关属性or方法可参考:Response

六、fetch和AbortController以及AbortSignal的兼容性如下:

image.png

image.png

七、总结:

本篇主要介绍了下:

1、fetch API的常规请求以及取消请求功能

2、可用于请求和响应的Headers, Request和Response构造函数

希望对大家有所帮助或启示,若有错误之处还请大家帮忙指出,感谢~