Fetch使用

326 阅读2分钟

fetch

核心接口:

  • fetch()
  • Response
  • Request
  • Headers

使用场景:

1. 抓取图片和上传图片
// 图片抓取
let response = await fetch(url, options);
let blob = await response.blob();
// 使用a标签承载下载功能
----------------------
// canvas绘图发送至服务器
canvasElem.toBlob((blob) => {
    fetch('xxxx', { method: 'POST', body: blob })
    .then(response => response.json())
    .then(result => alert(JSON.stringify(result, null, 2)))
}, 'image/png');

读取fetch响应结果的几种方式:

  • response.text()  —— 读取 response,并以文本形式返回 response
  • response.json()  —— 将 response 解析为 JSON 格式
  • response.formData()  —— 以 FormData 对象的形式返回 response
  • response.blob()  —— 以 Blob(具有类型的二进制数据)形式返回 response
  • response.arrayBuffer()  —— 以 ArrayBuffer(原始的二进制数据)形式返回 response
  • response.clone() —— 创建副本,实现多次读取
2. 跟踪下载进度

监听上传进度使用xhr; axios可用于监听上传、下载进度

使用api: typedArray + ReadableStream + blob/TextDecoder

const response = await fetch(xxxx);
const reader = response.body.getReader();  // 创建流读取器
const binaryChunks = [];  // 存储二进制数据块
let receivedLength = 0;

/* 计算数据块的总字节长度*/
const contentLength = response.headers.get('Content-Length');

/* 分块读取数据 */
while(true) {
    // value为读取的数据块
    const {done, value} = await reader.read();
    if (done) {
        break;
    }
    binaryChunks.push(value);
    receivedLength += value.length;
}

/* 解析数据*/
// 使用类型化数组合并二进制数据块chunks, 并解码为字符串
let chunksAll = new Uint8Array(receivedLength);
let position = 0;
for(let chunk of binaryChunks) {
    chunksAll.set(chunk, position);
    position += chunk.length;
}

const result = new TextDecoder("utf-8").decode(chunksAll);
const commits = JSON.parse(result);

// 或者生成blob对象
const blob = new Blob(binaryChunks)
3. 中止请求
// 同时中止fetch请求与其他异步请求
let urls = [...];
let controller = new AbortController();
let ourJob = new Promise((resolve, reject) => {
    // 我们的任务
    ...
    controller.signal.addEventListener('abort', reject);
});
let fetchJobs = urls.map(url => fetch(url, { signal: controller.signal }));
let results = await Promise.all([...fetchJobs, ourJob]);

// controller.abort() 被从任何地方调用
// 它都将中止所有 fetch 和 ourJob
4. keepalive

用户离开网页时,脚本向服务器提交一些用户行为的统计信息

window.onunload = function() {
  fetch('/analytics', {
    method: 'POST',
    body: "statistics",
    keepalive: true   // 页面卸载时,保持连接继续发送数据
  });
};

fetch与xhr区别:

  • fetch基于promise实现
  • fetch采用模块化设计,api分散在多个对象上
  • fetch通过数据流(Stream 对象)处理数据,可以分块读取,有利于提高网站性能表现,对于请求大文件或者网速慢的场景相当有用; 例如视频缓冲区、图像逐步加载显示
  • fetch监听下载进度,ajax跟踪上传进度
跨域处理

主流的跨域解决方案:CORS

// 跨域请求分为安全请求、非安全请求

// 安全请求(get、post等简单请求)
后台配置: 
-  Access-Control-Allow-Origin

// 非安全请求(patch、delete等请求或者携带特殊的请求头), 请求之前会进行预检请求(preflight)
1. 预检请求
请求头配置:
-  Access-Control-Request-Method: xxx
-  Access-Control-Request-Headers: xxx
预检响应:
-  Access-Control-Allow-Origin: xxx
-  Access-Control-Allow-Methods: xxx
-  Access-Control-Allow-Headers: xxx
-  Access-Control-Max-Age:xxx   // 缓存预检权限, 保证后续请求不触发预检

2. 实际请求发出
// fetch支持跨域
fetch(url, { mode: 'cors' })
在service worker中使用

参考链接: Stream_Api跨域--Fetch常见的跨域解决方案service worker