FetchAPI 请求流式数据 基本用法
请求 & 请求取消
src\api\fetch.ts
// 创建一个 AbortController 实例,用于取消请求
const controller = new AbortController();
const signal = controller.signal;// 封装整个请求
// url:要请求的接口
// content:要发送的问题参数
// onMessageReceived:流式数据获取成功后的回调函数
// end:流式数据获取结束后的回调函数
export const fetchStreamData = async (url: any,content: any,onMessageReceived: any,end: any
) => {try {// 发起fetch请求const response = await fetch(url, {method: 'POST',headers: {'Content-Type': 'application/json',},body: JSON.stringify(content),signal,});const reader = response.body.getReader(); // 流式数据读取器let decoder = new TextDecoder(); // 解码器// 数据let buffer = '';while (1) {// 异步读取const { done, value } = await reader.read();if (done) {//全部获取流式数据结束后的操作end();break;}// 将读取到的数据添加到缓冲区(可能是因为客户端处理数据的速度比服务器发送数据的速度快,//导致一次性接收到多条数据。这时候就要用buffer缓冲区来处理一下)//后端给我的数据格式:{"chunk_message": "我是数据"}// 流式处理:当数据以分块形式传输(如网络流、文件分块读取等),每个数据块可能包含字符的一部分字节。// stream设置为 true 时,解码器会保留未完成字符的字节,与下一块数据合并解码,避免乱码。 // stream 默认值为 false,适用于非流式数据(如完整文件或一次性接收的数据)。buffer += decoder.decode(value, { stream: true });// 尝试解析每条消息let startIndex = buffer.indexOf('{');let endIndex = buffer.indexOf('}', startIndex);while (startIndex !== -1 && endIndex !== -1) {const resultData = buffer.substring(startIndex, endIndex + 1);buffer = buffer.substring(endIndex + 1); // 移除已处理的数据// 寻找下一条消息的起始位置startIndex = buffer.indexOf('{');endIndex = buffer.indexOf('}', startIndex);// 定义正则表达式来匹配 chunk_message 的值,我们只要chunk_message对应的值//因为json数据和text/event-stream数据不同,json数据可以通过.访问chunk_message 的值,//但是text/event-stream数据是个纯文本,不能通过.访问chunk_message,我们用正则表达式来获取需要的数据let pattern = /"chunk_message"\s*:\s*"([^"]*)"/;// 使用正则表达式进行匹配let match = resultData.match(pattern);if (match) {// 提取匹配到的值let chunkMsg = match[1];// 将消息传递给回调函数处理onMessageReceived(chunkMsg);} else {// console.log("No chunk_message found");}}}} catch (error) {if (error.name === 'AbortError') {console.error('请求取消');} else {console.error('Fetch error:', error);}}
};
// 取消请求
export const abortedFetch = () => {controller.abort();
};