H5之流式(chunked)响应

文章介绍了在实时输出场景如商场首页中,如何利用流式(chunked)接口处理大量数据,以降低内存压力和优化网络传输。通过fetchAPI进行POST请求,展示了如何处理粘包问题,确保数据正确解析。同时指出,由于网络延迟可能导致粘包,前端需做处理,并提到axios需借助插件才能支持chunked传输。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

使用场景

  • 实时输出场景(GPT)
  • 数据实时要求比较高(商场首页)

使用原理

  • 流式(chunked)接口是一种处理大量数据的有效方式,特别是在需要处理大文件或长时间运行的任务时。这种接口允许数据分块逐步传输,而不是一次性将整个数据传输完成。这对于内存管理和网络传输来说都是非常有益的。
  • 使用fetch请求接口在循环等待接收数据,实现chunked接收。

H5用法

1、简单实现的例子: 实现application/json请求

const response = await fetch('/api/chunked', {
   method: 'POST',
    headers: {
        'Content-Type': 'application/json'
    },
    body: JSON.stringify({
        keyword: 'test-kw'
    })
});
if(response.body){
    const reader = response.body.getReader();
    while (true) {
        const { value, done } = await reader!.read();
        const msg = new TextDecoder().decode(value);
        console.log("接收的数据是=>" + msg);
        if (done) {
            break;
        }
    }  
}

2、实际的一个post请求例子(包括:粘包处理)

// 定义一个睡眠函数
const sleep = async function (time = 0) {
    await setTimeout(() => {}, time);
};
// 定义一个请求方法
const request = function (data: object, onChunkedReceived: (data) => void) {
    return new Promise((resolve, reject) => {
        (async () => {
        	// 记录接收的时间
            const startTime = new Date().getTime();
            const getUseTime = () => new Date().getTime() - startTime;
            // 开始请求
            const response = await fetch('/api/chunked', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json'
                },
                body: JSON.stringify(data)
            });
            if (response.body) {
                // 获取响应的内容reader
                const reader = response.body.getReader();
                let responseStr = '';
                const stickyTag = '}{';
                const parseResponse = function () {
                    // 粘包处理(后端定义为json字符串,那么粘包标记为:“}{”)之切割
                    const chunkedList = responseStr.split(stickyTag);
                    if (chunkedList.length > 0) {
                        //  粘包处理,补齐分包
                        const newChunkeds = chunkedList.map((it, i) => {
                            let str = it;
                            if (i > 0) str = '{' + str;
                            if (i < chunkedList.length) str += '}';
                            return str;
                        });
                        // 分别对分包处理并且回调
                        newChunkeds.forEach((chunked, i) => {
                            try {
                                // 后端定义:每个分包为json字符串
                                const json = JSON.parse(chunked);
                                onChunkedReceived(json);
                            } catch (err) {
                                if (i === newChunkeds.length - 1) {
                                    // 最后一个chunked没有解析,可能是chunked不完整,需要记录到
                                    responseStr = chunked;
                                } else {
                                    // 如果非最后一个chunked没有解析,那么内容有问题,那么就丢弃
                                    console.error('chunked解析错误,已经丢弃=>', chunked);
                                }
                            }
                        });
                    } else {
                        console.error('响应分割失败', { responseStr, chunkedList });
                    }
                };
                // 建立循环,等待内容读取完毕
                while (true) {
                    const { value, done } = await reader!.read();
                    const msg = new TextDecoder().decode(value);
                    console.log('粘包的个数=>', msg.split(stickyTag).length - 1, '接收的时间=>' + getUseTime());
                    responseStr += msg;
                    parseResponse();
                    await sleep(1);
                    if (done) {
                        break;
                    }
                }
                resolve({ msg: '接收数据完毕' });
            } else {
                reject({ msg: '发起请求错误', data: response });
            }
        })();
    });
};

特别注意

  • 粘包方面: 接口在发送chunked速度过快时候,可能会导致前端接收的数据粘在一起,那么前端就得进行粘包处理。网络速度慢也会导致粘包,综合来说:前端需要对接收的chunked进行粘包处理(不管接收的什么结果)
  • 每次等待读取响应结果间隙建议睡眠一段时间再继续获取。如果连续获取,可能会导致chunked处理结果问题。
  • axios不支持chunked形式,如果一定需要用,需要用到axios对应的chunked插件。

流处理相关文章

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

光速度的进程

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值