Fetch
fetch 是浏览器提供的一个用于发起网络请求的 API,是 XMLHttpRequest 的替代方案,fetch 本身自带 Promise 属性,支持现代化的异步方案。
但是注意,📢,虽然 fetch 返回值是 Promise,但是 HTTP 响应的异常状态(404, 502……非 200 状态段)并不会标记为 reject,而是 resolve 一个 false 值,只有在网络请求失败时才会标记为 reject。
在fetch出现之前我们经常会使用基于 XHR 封装的 axios,现在 fetch 补全了浏览器请求的短板,我们可以使用 fetch 来做为请求工具,我们可以基于 fetch 来做一个封装。
const initialHeaders = { 'Content-Type': 'application/json', } /** * * @param {string} method 请求方法 * @param {string} url 请求地址 * @param {string} body 请求数据 * @Param {Headers} headers 请求头 */ async function request(method, url, body, headers = initialHeaders) { // 请求拦截 const response = await fetch(url, { method, headers, body }) // 响应拦截 if (response.status > 299) { // error fix } return response.json() } function get(url, params = {}) { return request('GET', `${url}?${getQueryString(params)}`) } function post(url, body = {}) { return request('POST', url, JSON.stringify(body)) } function getQueryString(queryObj) { return Object.keys(queryObj) .map((key) => { const value = queryObj[key]; return `${key}=${value}`; }) .join('&'); } 复制代码
Headers
这里的 headers 直接用对象的形式写入的,其实 Fetch API 还提供了Header 构造器,很不方便但是有些功能限制在 ServiceWorker 中使用。
const initialHeaders = Headers.Headers({ 'Content-Type': 'application/json', }) initialHeaders.set('Authorization', 'xxxx') initialHeaders.append('Content-Type', 'charset=utf-8') initialHeaders.get('Accept') initialHeaders.has('Accept') 复制代码
- append:给 header 添加一个值或者添加一个不存在的 header 并赋值;
- delete:从 Headers 对象中删除指定 header;
- entries:返回 Headers 对象中所有的键值对;
- get:从 Headers 对象中返回指定 header 的全部值;
- has:从 Headers 对象中返回是否存在指定的 header;
- keys:返回 Headers 对象中所有存在的 header 名;
- set:替换现有的 header 的值,或者添加一个未存在的 header 并赋值;
- values:返回 Headers 对象中所有存在的 header 的值。
set 和 append 的区别在于,set 会覆盖之前的值,append 会在原有的值后追加;
例如
content-type: application/javascript; charset=utf-8
可以通过 append 添加两段或者直接用 set 添加一段
headers.set('content-type', 'application/javascript; charset=utf-8')
headers.append('Content-Type', 'application/javascript')
headers.append('Content-Type', 'charset=utf-8')
Request & Response
featch 的第一个参数可以是 Request 类型,也可已通过构造函数创建,参数就是 fetch 的参数,但是基本上不会手动创建。
fetch 的返回值是一个 Response 类型的对象,response最常见的属性有:
status:HTTP 的状态码;
statusText:和 status 对应的文本;
body:响应体;
一般 fetch 用于请求 json 数据,可以通过 json 方法将返回结果解析为 json,该方法是一个异步方法,返回结果是一个 Promise 对象。除此之外可以使用 text 将结果解析为文本,使用 blob 方法将结果解析问 Blob 文件流,结果均为 Promise 对象。
使用 clone 方法可以克隆一个响应体,本体和克隆体完全一致,但是存储在不同的变量中,Request 同样支持 clone。
中断请求
axios 中支持中断请求,fetch 中同样支持,我们可以使用AbortController来中断 Web 请求。
fetch 的参数中支持传入一个 single,只需要要将 AbortController 对象的single 属性传入,即可使用该AbortController 的 abort 方法来中断这个请求。
let controller; function fetchFile(url) { controller = new AbortController() const single = controller.signal fetch(url, { single }).then(res => { console.log('下载成功') return res }) } function stop() { if (controller) { controller.abort() console.log('下载中止') } } 复制代码
Cache
Cache API 是用于缓存的 API,目前的浏览器支持也算是比较完全
Cache 为 Request 和 Response 对象提供了存储机制,最常用的场景是在 ServiceWorker 中使用,虽然Cache 是 ServiceWorker 标准中的,但是 Cache 并不是限制在 ServiceWorker 中使用。
但是,Cache 只限制在 HTTPS 环境下使用。
在使用缓存之前需要使用 CacheStorage(使用 caches 访问) 的 open 方法打开一个命名空间,返回值是一个 Promise 对象,resolve的结果是 cache 缓存对象,同一个域名下可以有多个缓存对象。
caches 有以下方法:
- match:【request, options】检查指定的 request 是否是 cache 对象的键,返回一个resolve 为该匹配的Promise对象;
- has:【cacheName】如果存在 cacheName 的缓存对象则返回一个 Promise对象,resolve 的值为 true,否则为 false;
- open:【cacheName】返回与 cacheName 匹配的 cache 对象(Promise),如果不存在则创建一个缓存对象并返回;
- delete:【cacheName】删除与指定cacheName 匹配的 cache 对象,删除成功返回一个 Promise对象,resolve 值为 true,否则为 false;
- keys:返回caches 所有命名组成的数组。
cache 实例上有以下方法:
- match:【request, options】返回一个 Promise对象,resolve 的结果是跟 Cache 对象匹配的第一个缓存请求;
- matchAll:【request, options】返回一个 Promise对象,resolve 的结果是跟 Cache 对象匹配的缓存请求数组;
- add:【request】抓取一个 url,然后将相应进行缓存
- addAll:【requests】抓取一个url 数组,然后将返回的 response 缓存
- put:【request, response】同时抓取一个 request 和 response 进行缓存
- delete:【request, options】删除 key 为 request 的缓存,返回结果是一个 Promise 对象,删除成功 resolve 的值为 true,如果没有找到 resolve 的值为 false;
- keys:【request, options】返回一个 Promise对象,resolve 的值为 Cache key组成的数组,如果指定了 request则返回对应的Request
具体的使用案例之前在 ServiceWorker 那一篇中已经写过了。