Fetch API

浏览器实现的Fetch API 提供了一个获取资源的接口(包括跨域)

◉ 引言

  • 它是什么?
  • 为什么要使用它?
    • 它能解决什么问题?
    • 它在解决问题上有什么优势?
    • 它有哪些劣势?
  • 怎么使用它?
  • 最佳实践和封装

1. 它是什么?

浏览器窗口对象 window 下挂载的 fetch() 方法用于发起获取资源的请求。它返回一个 Promise,这个 Promise 会在请求响应后被resolve,并传回 Response 对象。

类似于传统的Ajax. 传统的Ajax是指XMLHttpRequest

2. 为什么使用它?

Fetch API 是**基于 ES6 Promise 设计**,对 generator/yield,async/await 友好。

2.1 优点

  • 语法简洁,语义清晰;
  • 基于标准Promise实现,支持async/await
  • 不需要依赖第三方库,就可以优雅地使用Ajax
  • 同构方便(基于http构建后端[node]fetch);

2.2 缺点

  • API的痛点:兼容性问题(polyfill)后面细说;
  • 没有process
  • 没有cancelabort
  • 没有timeout

3. 怎么使用它?

Fetch API 提供的一组对象,包括了 Headers, Request, Response, fetch

3.1 介绍

// XMLHttpRequest 发送异步请求
var xhr = new XMLHttpRequest()
xhr.open('GET', url)
xhr.responseType = 'json'
xhr.onload = () => console.log(xhr.response)
xhr.onerror = error => console.error(error)
xhr.send()

---------------- 华丽的分割线 ----------------

// Fetch 发送异步请求
const myHeaders = new Headers()
// 添加请求头内容
myHeaders.append('Content-Type', 'text/xml')

const myRequest = new Request(url,{
    headers: myHeaders,
    // 或者字面量
    // headers: {
    //     'Content-Type': 'text/xml',
    // },
})

// 请求
fetch(myRequest)
// 或者
// fetch(myRequest, {headers: myHeaders})
	.then(response => response.json())
    .then(result => console.log(result))
    .catch(error => console.error(error))

// 或(在 async 函数中)
try {
    let result = await fetch(myRequest)
    console.log(result)    
} catch (error) {
    console.error(error)
}

先看一下 Fetch 原生支持率:

image

原生支持率并不高,引入下面这些polyfill后可以完美支持 IE8+ :

Fetch polyfill的基本原理是探测是否存在 window.fetch 方法,如果没有则用XHR实现。这也是 github/fetch 的做法,但是有些浏览器(Chrome 45)原生支持Fetch,但响应中有中文时会乱码,老外又不太关心这种问题,所以我自己才封装了 fetch-detectorfetch-ie8 只在浏览器稳定支持Fetch情况下才使用原生Fetch

3.2 fetch

Promise<Response> fetch(input[, init])
/**
* @params { string|object } input
* @return { promise }
*/
fetch(input[, init])
3.2.1 input

此参数设置的为你想要访问的资源,可以是:

  • String 你想获取的资源地址
  • Request 对象
3.2.2 init 可选参数

此参数包含了针对此次请求的自定义设置,包含以下设置:

  • * method 请求类型,e.g. GET, POST;
  • * headers 请求头参数,自定义对象或者 new Headers
  • body 请求体,GET 和 HEAD 请求没有;
  • * mode 请求模式,请求跨域的控制,可选参数:
    • cors :该模式支持跨域请求,顾名思义它是以CORS的形式跨域;当然该模式也可以同域请求不需要后端额外的CORS支持;其对应的response typecors
      • cors 支持 三种content-type不支持 application/json(希望有同学分享下这个三个的区别)
        • application/x-www-form-urlencoded
        • multipart/form-data
        • text/plain
    • no-cors :该模式用于跨域请求但是服务器不带CORS响应头,也就是服务端不支持CORS;这也是fetch的特殊跨域请求方式;其对应的response typeopaque
    • same-origin :该模式是不允许跨域的,它需要遵守同源策略,否则浏览器会返回一个error告知不能跨域;其对应的response typebasic
  • credentials 认证信息,请求是否包含认证信息,可选参数:
    • omit 忽略(默认)
    • same-origin 同源请求带cookie
    • include 无论跨域还是同源请求都会带cookie
  • cache 请求缓存模式设置,常用:no-cache
  • redirect 请求被重定向的处理方式,常用:follow
  • referrer
  • referrerPolicy
  • integrity
  • keepalive
  • * signal 值应为 AbortSignal 的实例,用来与请求通讯并可以用 AbortController 取消请求

示例

fetch('https://www.baidu.com', {
    mode: 'cors',
    referer: 'https://www.baidu.com'
}).then(res => console.log(res, res.text()))
3.2.3 fetch中的坑
  • Fetch请求默认是不带cookie的,需要设置 fetch(url, {credentials: 'include'})
  • 服务器返回 400,500 错误码时并不会 reject,只有网络错误这些导致请求不能完成时,fetch 才会被 reject。

3.3 Headers

3.3.1 构造函数

window.Headers,用于构建请求头内容,接口允许您对HTTP请求和响应头执行各种操作。 包括检索,设置,添加和删除。

const myHeaders = new Headers()
3.3.2 方法
  • Headers.append()

​ 给现有的header添加一个值, 或者添加一个未存在的header并赋值.

  • Headers.delete()

    从Headers对象中删除指定header.

  • Headers.entries()

    迭代器 的形式返回Headers对象中所有的键值对.

  • Headers.get()

    从Headers对象中返回指定header的第一个值.

  • Headers.getAll()

    以数组的形式从Headers对象中返回指定header的全部值.

  • Headers.has()

    以布尔值的形式从Headers对象中返回是否存在指定的header.

  • Headers.keys()

    迭代器 的形式返回Headers对象中所有存在的header名.

  • Headers.set()

    替换现有的header的值, 或者添加一个未存在的header并赋值.

  • Headers.values()

    迭代器 的形式返回Headers对象中所有存在的header的值.

const myHeaders = new Headers()

myHeaders.append('Content-Type', 'text/xml')

myHeaders.get('Content-Type')
// 返回 'text/xml'

3.4 Request

参考fetch部分

3.5 Response

3.5.1 构造函数

window.Response,fetch请求返回的数据都是Response的实例

const myResponse = new Response()
3.5.2 属性
  • Response.type

​ 包含Response的类型 (例如, basic, cors).

  • Response.url

​ 包含Response的URL.(可能被redirect后的地址)

  • Response.useFinalURL

​ 包含了一个布尔值来标示这是否是该Response的最终URL.

  • Response.status

​ 包含Response的状态码 (例如, 200 成功).

  • Response.ok

​ 包含了一个布尔值来标示该Response成功(状态码200-299) 还是失败.

  • Response.redirected

​ 表示该Response是否来自一个重定向,如果是的话,它的URL列表将会有多个

  • Response.statusText

​ 包含了与该Response状态码一致的状态信息 (例如, OK对应200).

  • Response.headers

​ 包含此Response所关联的 Headers 对象.

  • Response.body

​ 包含此Response所包含的内容.

  • Body.bodyUsed

​ 包含了一个布尔值来标示该Response是否读取过Body.

3.5.3 方法
  • Response.clone()

    创建一个Response对象的克隆

  • Response.error()

    返回一个绑定了网络错误的新的Response对象

  • Response.redirect()

    用另一个URL创建一个新的 response.

Response 实现了Body 所以以下方法同样可用

  • Body.arrayBuffer()

    读取 Response 对象并且将它设置为已读(因为Responses对象被设置为了 stream 的方式,所以它们只能被读取一次) ,并返回一个被解析为ArrayBuffer格式的promise对象

  • Body.blob()

    读取 Response 对象并且将它设置为已读(因为Responses对象被设置为了 stream 的方式,所以它们只能被读取一次) ,并返回一个被解析为Blob格式的promise对象

  • Body.formData()

    读取 Response 对象并且将它设置为已读(因为Responses对象被设置为了 stream 的方式,所以它们只能被读取一次) ,并返回一个被解析为FormData格式的promise对象

  • Body.json()

    读取 Response 对象并且将它设置为已读(因为Responses对象被设置为了 stream 的方式,所以它们只能被读取一次) ,并返回一个被解析为JSON格式的promise对象

  • Body.text()

    读取 Response 对象并且将它设置为已读(因为Responses对象被设置为了 stream 的方式,所以它们只能被读取一次) ,并返回一个被解析为String 格式的promise对象,解析完整的 Response ,并返回一个 String 对象的promise

4. 最佳实践和封装

将在代码中演示…

Logo

CSDN联合极客时间,共同打造面向开发者的精品内容学习社区,助力成长!

更多推荐