Skip to content

Fetch

用于在 JavaScript 里发出 HTTP 请求。

javascript
fetch(url, options)

options

  • method 请求方法

    "GET"

    ...

  • headers 请求头

    { "Content-Type": "text/plain;charset=UTF-8" }

  • body 请求体

    'foo=foo&bar=bar'

    formData

    ...

  • referrer 设置 referer 标头,可以为任意字符串,也可以设为空字符串 (即不发送referer标头)。

    "about:client",

  • referrerPolicy 用于设定Referer标头的规则。

    属性可能的取值如下:

    • no-referrer-when-downgrade:默认值,总是发送Referer标头,除非从 HTTPS 页面请求 HTTP 资源时不发送。

    • no-referrer:不发送Referer标头。

    • origin:Referer标头只包含域名,不包含完整的路径。

    • origin-when-cross-origin:同源请求Referer标头包含完整的路径,跨域请求只包含域名。

    • same-origin:跨域请求不发送Referer,同源请求发送。

    • strict-origin:Referer标头只包含域名,HTTPS 页面请求 HTTP 资源时不发送Referer 标头。

    • strict-origin-when-cross-origin:同源请求时Referer标头包含完整路径,跨域请求时 只包含域名。

    • HTTPS:页面请求 HTTP 资源时不发送该标头。

    • unsafe-url:不管什么情况,总是发送Referer标头。

  • mode

    • cors:默认值,允许跨域请求。

    • same-origin:只允许同源请求。

    • no-cors:请求方法只限于 GET、POST 和 HEAD,并且只能使用有限的几个简单标头,不能添 加跨域的复杂标头,相当于提交表单所能发出的请求。

  • credentials

    • same-origin:默认值,同源请求时发送 Cookie,跨域请求时不发送。

    • include:不管同源请求,还是跨域请求,一律发送 Cookie。

    • omit:一律不发送。

  • cache: "default",

    • default:默认值,先在缓存里面寻找匹配的请求。

    • no-store:直接请求远程服务器,并且不更新缓存。

    • reload:直接请求远程服务器,并且更新缓存。

    • no-cache:将服务器资源跟本地缓存进行比较,有新的版本才使用服务器资源,否则使用缓存。

    • force-cache:缓存优先,只有不存在缓存的情况下,才请求远程服务器。

    • only-if-cached:只检查缓存,如果缓存里面不存在,将返回504错误。

  • redirect: "follow",

    • follow:默认值,fetch()跟随 HTTP 跳转。

    • error:如果发生跳转,fetch()就报错。

    • manual:fetch()不跟随 HTTP 跳转,但是response.url属性会指向新的 URL, response.redirected属性会变为true,由开发者自己决定后续如何处理跳转。

  • integrity: "",

    属性指定一个哈希值,用于检查 HTTP 回应传回的数据是否等于这个预先设定的哈希值。 比如,下载文件时,检查文件的 SHA-256 哈希值是否相符,确保没有被篡改。

  • keepalive: false,

    用于页面卸载时,告诉浏览器在后台保持连接,继续发送数据。

  • signal: undefined

    指定一个 AbortSignal 实例,用于取消fetch()请求。

GET

javascript
fetch('https://api.github.com/users/xnorain001')
  .then(response => {
    console.log(response)
    /*
      Response对象根据服务器返回的不同类型的数据,提供了不同的读取方法。
      response.text():得到文本字符串, 比如 HTML 文件。
      response.json():得到 JSON 对象。
      response.blob():得到二进制 Blob 对象。
      response.formData():得到 FormData 表单对象, 主要用在 Service Worker 里面,拦截用户提交的表单,修改某些数据以后,再提交给服务器。
      response.arrayBuffer():得到二进制 ArrayBuffer 对象, 主要用于获取流媒体文件。
      上面5个读取方法都是异步的,返回的都是 Promise 对象。必须等到异步操作结束,才能得到服务器返回的完整数据。

      Stream 对象只能读取一次,读取完就没了。这意味着,前一节的五个读取方法,只能使用一个,否则会报错。
      let text =  await response.text();
      let json =  await response.json();  // 报错
      先使用了response.text(),就把 Stream 读完了。后面再调用response.json(),就没有内容可读了,所以报错。
      response.clone()方法,创建Response对象的副本,实现多次读取。

      response.redirect()方法,用于将 Response 结果重定向到指定的 URL。该方法一般只用在 Service Worker 里面。

      response.body可以用来分块读取内容,应用之一就是显示下载的进度。
      const response = await fetch('flower.jpg');
      const reader = response.body.getReader();

      while(true) {
        const {done, value} = await reader.read();
        if (done) {
          break;
        }
        console.log(`Received ${value.length} bytes`)
      }
      response.body.getReader()方法返回一个遍历器。这个遍历器的read()方法每次返回一个对象,表示本次读取的内容块。
      这个对象的done属性是一个布尔值,用来判断有没有读完;value属性是一个 arrayBuffer 数组,表示内容块的内容,而value.length属性是当前块的大小。
    */

  }, reason => {
    console.log(reason)
  })

fetch 的响应(Response对象)

  • body: ReadableStream

    暴露响应的流

  • bodyUsed: false

    该 body 是否被使用过

  • headers: {}

    响应头

    • Headers.get():根据指定的键名,返回键值。

    • Headers.has(): 返回一个布尔值,表示是否包含某个标头。

    • Headers.set():将指定的键名设置为新的键值,如果该键名不存在则会添加。

    • Headers.append():添加标头。

    • Headers.delete():删除标头。

    • Headers.keys():返回一个遍历器,可以依次遍历所有键名。

      for(let key of Headers.keys()) { console.log(key); }

    • Headers.values():返回一个遍历器,可以依次遍历所有键值。

    • Headers.entries():返回一个遍历器,可以依次遍历所有键值对([key, value])。

    • Headers.forEach():依次遍历标头,每个标头都会执行一次参数函数。

  • ok: true

    HTTP 响应状态码范围 [200, 300) 时为 true, 其他情况为 false。

  • redirected: false

    请求是否发生过跳转

  • status: 200

    HTTP 响应状态码

  • statusText: "OK"

    HTTP 响应的状态信息

  • type: "cors"

    请求类型

    • basic:普通请求,即同源请求。

    • cors:跨域请求。

    • error:网络错误,主要用于 Service Worker。

    • opaque:如果 fetch() 请求的 type 属性设为 no-cors ,就会返回这个值,详见请求 部分。表示发出的是简单的跨域请求,类似<form>表单的那种跨域请求。

    • opaqueredirect:如果fetch()请求的redirect属性设为manual,就会返回这个值。

  • url: "https://api.github.com/users/xnorain001"

    请求url, 如果有跳转, 是最终的url

成功

fetch 请求只有网络错误,或者无法连接时,fetch() 才会报错,其他情况都不会报错,而是认为 请求成功。即使服务器返回的状态码是 4xx 或 5xx,fetch() 也不会报错(即 Promise 不会变 为 rejected 状态)。可以通过 Response.status 属性,得到 HTTP 回应的真实状态码,判断 请求是否成功。不用考虑网址跳转(状态码为 3xx),因为 fetch() 会将跳转的状态码自动转为 200。

javascript
if (response.status >= 200 && response.status < 300) {
  // ...
} else {
  // ...
}

// 也可以通过 response.ok 是否为 true 判断成功
if (response.ok) {
  // 请求成功
} else {
  // 请求失败
}

取消

javascript
// 首先新建 AbortController 实例
let controller = new AbortController();
let signal = controller.signal;
// 然后发送fetch()请求
fetch(url, {
  // 配置对象的signal属性必须指定接收 AbortController 实例发送的信号controller.signal。
  signal: controller.signal
});
signal.addEventListener('abort',
  () => console.log('abort!')
);
// controller.abort()方法用于发出取消信号。这时会触发abort事件,这个事件可以监听,
// 也可以通过controller.signal.aborted属性判断取消信号是否已经发出。
controller.abort(); // 取消
console.log(signal.aborted); // true


// 1秒后自动取消请求的例子

let controller = new AbortController();
setTimeout(() => controller.abort(), 1000);

try {
  let response = await fetch('/long-operation', {
    signal: controller.signal
  });
} catch(err) {
  if (err.name == 'AbortError') {
    console.log('Aborted!');
  } else {
    throw err;
  }
}