当前位置: 首页 > article >正文

taro + vue3 实现小程序sse长连接实时对话

前言

taro.request是可以实现sse长连接的,但是呢其中有俩大坑,找了许多资料也没解决,后续解决办法也与后端商量改用WebSocket来实现。

代码实现

SSEManager.js:

import { getAccessToken } from "../xx/xx";
import { TextDecoder } from 'text-encoding';
import Taro from "@tarojs/taro";
const regexp = /\[DONE\]/;   // 规定结束标志
const decoder = new TextDecoder("utf-8");/*** 外部需要限制SSE连接,无法获取时,自行处理**/
export function getSSEConnection(connectId,sessionId,messageEmitter,closeHandler
) {console.log("[SSE] getSSEConnection", connectId, sessionId);let token = getAccessToken();const requestTask = Taro.request({url:'http://xxxx:xx/chatConnect',method: "GET",data: { id: connectId },responseType: "arraybuffer",        // 响应的数据类型header: {Authorization: token,Accept: "text/event-stream",},enableChunked: true,                // 关键配置  开启后数据将以分块形式传输timeout:6 * 1000,                   // 该配置在sse中没用fail: (err) => {console.log("err", err);if (err.errMsg.includes("timeout")) {closeHandler('timeout');console.log('回答超时了',connectId, sessionId);} else {closeHandler('fail');console.log('回答出错了',connectId, sessionId);}}});// 接收到新的chunk时触发requestTask.onChunkReceived((chunk) => {const responseText = decoder.decode(chunk.data);let plain = responseText.replace(/^data:/gm, "");plain = plain.replace(/\n{2,}/g, "\n")    .replace(/^\n+|\n+$/g, "").trim();messageEmitter(sessionId, plain);if (regexp.test(responseText)) {console.log('回答完成',connectId, sessionId);closeHandler('complete');}});return requestTask
}

使用

import { getSSEConnection } from '../sse/SSEManager.js';
import mitt from 'mitt';
const eventBus = mitt();
const sessionId = ref () // 会话id
let chatconst chatSendEvent = async () => {eventBus.on(sessionId.value, (data) => {// 对获取的数据块处理console.log( data);chat += data});// 获取SSE链接getSSEConnectionEvent()
}const getSSEConnectionEvent = async () => {const globalId = nanoid(64); // 链接id 请求参数requestTaskCleanup.value = getSSEConnection(globalId,sessionId.value,(key, value) => { eventBus.emit(key, value); },async (why) => {console.log("[event] close!", why);if (why == 'complete') {}// TODO 超时 else if (why == 'timeout') {} else if (why == 'abort') {}else {}eventBus.all.clear();})// 发送提示词 sendStreamEvent(globalId)}

以上就是整个过程使用,其中的数据处理根据业务来定。现在来讲讲其中的坑:

坑 

超时无法捕获:

在开启分块传输后,timeout配置就不生效了,超时也无法捕获了。

解决:

自己设置定时器,在超时后断开连接,requestTask.abort(); 但是这个方法是无效的,无法断开。

参考以下文章,可知该问题是一直没得到解决的。 微信开放社区https://developers.weixin.qq.com/community/develop/doc/000caa13bd8fb080ed7d318fb57800

在前端无法主动断开连接的情况下,前端只能实现不接收后端返回的数据块,表面上看起来像是断开了连接。

实现代码如下(SSEManager.js):

超时的时候 通过一个变量状态来控制是否继续接收返回的数据块。当然也可以通过与后端设置一样的超时时间 通过后端的报错 来直接处理。

import { getAccessToken } from "../xx/xx";
import { TextDecoder } from 'text-encoding';
import Taro from "@tarojs/taro";
const regexp = /\[DONE\]/;const decoder = new TextDecoder("utf-8");
/*** 外部需要限制SSE连接,无法获取时,自行处理** **/
export function getSSEConnection(connectId,sessionId,messageEmitter,closeHandler
) {console.log("[SSE] getSSEConnection", connectId, sessionId);let token = getAccessToken();let shouldIgnoreData = false;  // 新增 控制是否接收数据块 为true 不接收//  新增 设置超时定时器const timeoutTimer = setTimeout(() => {if (!shouldIgnoreData) {closeHandler('timeout');cleanup();}}, 182 * 1000 );  //  保底报错结束  这里保底是指超时时间与后端设置一样的const requestTask = Taro.request({url: `http://xxxx:xx/chatConnect`,method: "GET",data: { id: connectId },responseType: "arraybuffer",header: {Authorization: token,Accept: "text/event-stream",},enableChunked: true,});// 新增 资源清理函数const cleanup = () => {if (shouldIgnoreData) return;shouldIgnoreData = true;  // 暂解决超时处理 忽略后续数据clearTimeout(timeoutTimer);// 终止请求--------TODO未终止// 取消监听获取数据块 与使用 shouldIgnoreData 变量来控制数据的接收是一样的 可选其一种方式requestTask.offChunkReceived(messageEmitter);   requestTask.abort();   // 不生效};//  新增 请求报错处理 返回函数requestTask.onHeadersReceived((res) => {console.log("SSE request onHeadersReceived:", res);if (shouldIgnoreData) return; // 终止后 忽略数据clearTimeout(timeoutTimer);if (res.statusCode !== 200) {closeHandler('fail');cleanup();}});requestTask.onChunkReceived((chunk) => {if (shouldIgnoreData) return; // 终止后忽略数据const responseText = decoder.decode(chunk.data);let plain = responseText.replace(/^data:/gm, "");plain = plain.replace(/\n{2,}/g, "\n")    .replace(/^\n+|\n+$/g, "").trim();messageEmitter(sessionId, plain);if (regexp.test(responseText)) {console.log('回答完成');closeHandler('complete');cleanup();}});// 返回函数 主动不接数据const f = () => {closeHandler('abort')cleanup();}return f
}

请求无法暂停:

由于requestTask.abort();   // 不生效 ,前端若想处理也可以通过以上行为 不接收返回数据

来实现,改变视觉效果。

总结

以上都是前端来实现的一种方式,在开发过程中以上问题也可以通过和后端配合来解决。

使用taro.request 和 wx.request 实现sse长连接 都是一样的坑(taro.request是基于wx.request封装的),建议改用WebSocket (自己也与后端商议改用了

有更多解决办法,欢迎评论区分享

相关文章:

taro + vue3 实现小程序sse长连接实时对话

前言 taro.request是可以实现sse长连接的,但是呢其中有俩大坑,找了许多资料也没解决,后续解决办法也与后端商量改用WebSocket来实现。 代码实现 SSEManager.js: import { getAccessToken } from "../xx/xx"; import { TextDecode…...

使用MATLAB求解微分方程:从基础到实践

使用MATLAB求解微分方程:从基础到实践 微分方程是描述自然界和工程领域中许多现象的重要数学工具。MATLAB提供了强大的工具来求解各种类型的微分方程。本文将介绍如何使用MATLAB求解常微分方程(ODE)。 1. 基本ODE求解器 MATLAB提供了多种ODE求解器,最…...

基于MATLAB的大规模MIMO信道仿真

1. 系统模型与参数设置 以下是一个单小区大规模MIMO系统的参数配置示例,适用于多发多收和单发单收场景。 % 参数配置 params.N_cell 1; % 小区数量(单小区仿真) params.cell_radius 500; % 小区半径(米&#xff09…...

如何在 Windows 和 Mac 上擦拭和清洁希捷外置硬盘

希捷外置硬盘广泛用于存储目的,但有时您可能出于多种目的需要擦除或清洁希捷外置硬盘,例如转售、重复使用、捐赠等。为了释放硬盘上的存储空间或确保没有人可以从硬盘中恢复您的信息,擦除硬盘是必要的步骤。无论您使用的是 Windows 还是 Mac&…...

Vue 3.0 中状态管理Vuex 与 Pinia 的区别

在 Vue.js 应用开发中,状态管理是构建复杂应用的关键环节。随着 Vue 3 的普及和 Composition API 的引入,开发者面临着状态管理库的选择问题:是继续使用经典的 Vuex,还是转向新兴的 Pinia?本文将从设计理念、API 设计、…...

第三届黄河流域网安技能挑战赛复现

Web 奶龙牌图片处理器2.0 这题,之前只了解过 .user.ini 文件,并为遇到实操题 但赛前差点就做到下面这题了,不多说,复现之前先看看下面这题 靶场: 攻防世界 没错,又做上文件上传题了,别看…...

python 生成复杂表格,自动分页等功能

python 生成复杂表格,自动分页等功能 解决将Python中的树形目录数据转换为Word表格,并生成带有合并单元格的检测报告的问题。首先,要解决“tree目录数据”和“Word表格互换”,指将树…...

2025年高防IP与游戏盾深度对比:如何选择最佳防护方案?

2025年,随着DDoS攻击规模的指数级增长和混合攻击的常态化,高防IP与游戏盾成为企业网络安全的核心选择。然而,两者在功能定位、技术实现及适用场景上存在显著差异。本文结合最新行业实践与技术趋势,全面解析两者的优劣,…...

在 Vue + Vite 项目中,直接使用相对路径或绝对路径引用本地图片资源时,图片无法正确显示。

Vue 项目中静态资源引用问题 1.问题描述 在 Vue Vite 项目中,直接使用相对路径或绝对路径引用本地图片资源时,图片无法正确显示。 错误示例 javascript // 错误方式1:使用相对路径 const products [ { name: iPhone 14 Pro, image: .…...

判断手机屏幕上的横向滑动(左滑和右滑)

在JavaScript中,你可以通过监听触摸事件(touch events)来判断用户在手机屏幕上的横向滑动方向。以下是实现方法: 基本实现方案 let touchStartX 0; let touchEndX 0;function handleTouchStart(event) {touchStartX event.ch…...

用户有一个Django模型没有设置主键,现在需要设置主键。

用户有一个Django模型没有设置主键,现在需要设置主键。 from django.db import modelsclass CategoryAssistentModel(models.Model):second_level_category models.CharField(max_length100, nullTrue, blankTrue)third_level_category models.CharField(max_len…...

【文献阅读】EndoChat: Grounded Multimodal Large Language Model for Endoscopic Surgery

[2501.11347] EndoChat: Grounded Multimodal Large Language Model for Endoscopic Surgery 2025年1月 数据可用性 Surg-396K 数据集可在 GitHub - gkw0010/EndoChat 公开获取。 代码可用性 EndoChat 的代码可在 GitHub - gkw0010/EndoChat 下载。 摘要 近年来&#xff…...

React JSX语法介绍(JS XML)(一种JS语法扩展,允许在JS代码中编写类似HTML的标记语言)Babel编译

在线调试网站:https://zh-hans.react.dev/learn 文章目录 JSX:现代前端开发的声明式语法概述JSX的本质与工作原理什么是JSXJSX转换流程 JSX语法特性表达式嵌入(JSX允许在大括号内嵌入任何有效的JavaScript表达式)属性传递&#xf…...

【R语言编程绘图-箱线图】

基本箱线图绘制 使用ggplot2绘制箱线图的核心函数是geom_boxplot()。以下是一个基础示例,展示如何用iris数据集绘制不同物种(Species)的萼片长度(Sepal.Length)分布: library(ggplot2) ggplot(iris, aes(…...

【elasticsearch 7 或8 的安装及配置SSL 操作指引】

1.标题获取安装文件 cd /opt/tools wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-8.11.4-linux-x86_64.tar.gz tar -zxvf elasticsearch-8.11.4-linux-x86_64.tar.gz mv /opt/tools/elasticsearch-8.11.4 /opt/elasticsearch #配置vm.max_map_co…...

GitHub 趋势日报 (2025年05月23日)

本日报由 TrendForge 系统生成 https://trendforge.devlive.org/ 🌐 本日报中的项目描述已自动翻译为中文 📈 今日整体趋势 Top 10 排名项目名称项目描述今日获星总星数语言1All-Hands-AI/OpenHands🙌开放式:少代码,做…...

MongoDB索引:原理、实践与优化指南

为什么索引对数据库如此重要? 在现代应用开发中,数据库性能往往是决定用户体验的关键因素。想象一下,当你在电商平台搜索商品时,如果每次搜索都需要等待5-10秒才能看到结果,这种体验是多么令人沮丧。MongoDB作为最流行…...

SQL实战之索引优化(单表、双表、三表、索引失效)

文章目录 单表优化双表优化三表优化结论索引失效 单表优化 总体原则:建立索引并合理使用,避免索引失效 案例说明:查询category_ id 为1且comments大于1的情况下,views最多的article_ id: 传统方案: explain select id, author_ id…...

[7-1] ADC模数转换器 江协科技学习笔记(14个知识点)

1 2 3 4 5 6 7 8 9 10 11 12 13 14 DMA(Direct Memory Access,直接内存访问)是一种硬件特性,它允许某些硬件子系统直接访问系统的内存,而无需CPU的介入。这样,CPU就可以处理其他任务,从而提高系…...

SSM整合:Spring+SpringMVC+MyBatis完美融合实战指南

前言 在Java企业级开发领域,SSM(SpringSpringMVCMyBatis)框架组合一直占据着重要地位。这三个轻量级框架各司其职又相互配合,为开发者提供了高效、灵活的开发体验。本文将深入探讨SSM框架的整合过程,揭示整合背后的原…...

Spring Boot分页查询进阶:整合Spring Data REST实现高效数据导航

目录: 引言分页查询基础回顾 2.1 Spring Data JPA分页接口 2.2 Pageable与Page的使用 2.3 常见分页参数设计Spring Data REST简介 3.1 HATEOAS与超媒体驱动API 3.2 Spring Data REST核心功能 3.3 自动暴露Repository接口整合Spring Boot与Spring Data REST 4.1 项目…...

阿里云 Serverless 助力海牙湾构建弹性、高效、智能的 AI 数字化平台

作者:赵世振、十眠、修省 “通过阿里云 Serverless 架构,我们成功解决了弹性能力不足、资源浪费与运维低效的痛点。SAE 的全托管特性大幅降低技术复杂度。未来,我们将进一步探索 Serverless 与 AI 的结合,为客户提供更智能的数字…...

升级node@22后运行npm install报错 distutils not found

从node20升级到node22后,在运行 npm install 的时候报了很多 gyp 错误,其中包括 npm error npm error ModuleNotFoundError: No module named distutils。 问题原因是我在使用 brew install node22 的过程中自动把 python 升级到了 3.13。而 distutils …...

一个开源的多播放源自动采集在线影视网站

这里写自定义目录标题 欢迎使用Markdown编辑器GoFilm简介项目部署1、前置环境准备1.2 redis 配置 film-api 后端服务配置将 GoFilm 项目根目录下的 film 文件夹上传到 linux 服务器的 /opt 目录下 2. 构建运行1. docker 部署1.1 安装 docker , docker compose 环境 注意事项: 2…...

【PhysUnits】10 减一操作(sub1.rs)

一、源码 代码实现了一个类型级别的减一操作(Sub1 trait),通过Rust的类型系统在编译期完成数值减一的计算。 //! 减一操作特质实现 / Decrement operation trait implementation //! //! 提供类型级别的减一计算 / Provides type-level decrement operationuse su…...

深度检测与动态透明度控制 - 基于Babylon.js的遮挡检测实现解析

首先贴出实现代码: OcclusionFader.ts import { AbstractEngine, Material, type Behavior, type Mesh, type PBRMetallicRoughnessMaterial, type Scene } from "babylonjs/core"; import { OcclusionTester } from "../../OcclusionTester"…...

Linux下使用socat将TCP服务转为虚拟串口设备

Linux下使用socat将TCP服务转为虚拟串口设备 socat是一个强大的网络工具,可以将TCP连接转换为虚拟串口设备,这在嵌入式开发、工业控制等领域非常有用。下面详细介绍如何实现这一功能。 基本原理 socat可以通过创建伪终端(PTY)来模拟串口设备&#xff…...

docker push 报错 denied: requested access to the resource is denied

问题&#xff1a;当 docker logout -> docker login 用户登录&#xff0c;但仍然无法 docker push $ docker push <username>/nginx-custom:v1 The push refers to repository [docker.io/jagger/nginx-custom] 340e6d3ea0c7: Preparing 941dd9dd8ee4: Preparing f6…...

epub→pdf | which 在线转换??好用!!

1、PDF派&#xff08;free&quick) pdf转word_pdf转换成excel_pdf转换成ppt _纬来PDF转换器 评价&#xff1a;目前使用免费&#xff0c;转化的时候有进度条提示&#xff0c;总的来说比较快&#xff0c;50mb的文件在40秒内可以转换完成&#xff0c;推荐 2、pdfconvert(free…...

PBX、IP PBX、FXO 、FXS 、VOIP、SIP 的概念解析以及关系

PBX&#xff08;Private Branch Exchange&#xff09; 概念 &#xff1a;PBX 是专用交换机&#xff0c;是一种在企业或组织内部使用的电话交换系统。它允许内部用户之间以及内部用户与外部公共电话网络&#xff08;PSTN&#xff09;之间进行通信。例如&#xff0c;在一个大型企…...