vue使用post请求处理接口返回EventStream数据并进行展示

之前已经发过简单使用get请求接口EventStream数据:
vue处理接口返回EventStream数据并进行展示

使用post请求接口EventStream数据具体操作如下:

使用sse.js第三方插件实现:

安装sse.js:

javascript 复制代码
npm install sse

vue页面代码:

javascript 复制代码
import { SSE } from 'sse.js';
import { parseMarkdown } from '@/utils/markdownParser'
export default {
	name: "chat",
	data() {
		return {
			sseFun: null,
		};
	},
	methods: {
		// 使用 sse.js 实现
		connectSSEJS(data){
			let token = window.sessionStorage.getItem('token');
			let para = {
				参数1: 参数1的值,
				参数1: 参数2的值,
			}
			this.sseFun = new SSE(`接口地址`, {
				method: 'POST',
				payload: JSON.stringify(para),
				headers: {
					'Content-Type': 'application/json;charset=utf-8',
					'token': `${token}`
				},
			});
			let that = this;
			let _webSearchResultList = [];
			this.sseFun.onmessage = (event) => {
				// console.log('收到消息:', event.data);
				let _data= JSON.parse(this.decodeBase64ToUtf8(event.data));
				if(_data.state==='start'){
					// 接收数据的第一条标识:state为start(具体根据接口返回的情况进行判断),可储存或处理一些数据
				}
				// 对接收到的数据进行处理
				let dealTxt = String(_data.message);
				const newText = dealTxt.replace(/\$ref_(\d+)/g, (match, number) => {
					return `<span class="webmark" style="background: rgb(255, 232, 230);
					color: rgb(230, 0, 19);
					padding: 1px 8px;
					border-radius: 10px;
					margin-right: 4px;" 
					data-link="${_webSearchResultList.find(i=>i.refer == match).link}" 
					data-title="${_webSearchResultList.find(i=>i.refer == match).title}">网页 ${number}</span>`;
				});
				// 此处的parseMarkdown用于解析和渲染Markdown文本,具体代码在下面
				this.streamText = parseMarkdown(String(newText.replace(/\\\[/g, '$$$').replace(/\\\]/g, '$$$')));
				if(!_data.id){
					// 不存在id,认为数据返回完成
				}
			};
		},
		// 断开SSE连接
		disconnectSSE() {
			if (this.sseFun) {
				this.sseFun.close(); // 关闭SSE连接
				this.sseFun = null; // 清除引用,防止内存泄漏
			}
		},
	}
}

用于解析和渲染Markdown文本的markdownParser文件内容:

javascript 复制代码
import MarkdownIt from 'markdown-it'
import mk from 'markdown-it-katex';  // 匹配数学公式
import sanitizer from "markdown-it-sanitizer";
import hljs from 'highlight.js'; // 匹配代码
import DOMPurify from 'dompurify'

// 初始化 Markdown 解析器
const md = new MarkdownIt({
  html: true,         // 允许 HTML 标签
  linkify: false,      // 自动转换链接
  typographer: true,  // 优化排版
  tabels: true,       // 允许表格

  highlight: (str, lang) => {  // 代码高亮
    // 代码高亮逻辑
    if (lang && hljs.getLanguage(lang)) {
      try {
        return `<pre class="hljs"><code>${
          hljs.highlight(str, { language: lang, ignoreIllegals: true }).value
        }</code></pre>`;
      } catch (__) {}
    }
    // 未指定语言时,自动检测
    return `<pre class="hljs" style="background: #fafafa;"><code>${hljs.highlightAuto(str).value}</code></pre>`;
  }
})
md.use(mk, {
  macros: {
    // 物理符号
    "\\e": "\\mathrm{e}",
    "\\ii": "\\mathrm{i}",
    "\\dd": "\\mathop{}\\!\\mathrm{d}",
    "\\bra": ["\\left\\langle #1 \\right|", 1],
    "\\ket": ["\\left| #1 \\right\\rangle", 1],
    "\\vect": ["\\mathbf{#1}", 1],
    "\\tensor": ["\\underline{\\underline{#1}}", 1],
    "\\ev": ["\\left\\langle #1 \\right\\rangle", 1],
    
    // 数学符号
    "\\Z": "\\mathbb{Z}",
    "\\Q": "\\mathbb{Q}",
    "\\C": "\\mathbb{C}",
    "\\R": "\\mathbb{R}",
    "\\abs": ["\\left| #1 \\right|", 1],
    "\\pd": ["\\frac{\\partial #1}{\\partial #2}", 2],
    "\\matrix": "\\begin{pmatrix} #1 \\\\ #2 \\end{pmatrix}",
    "\\pmatrix": ["\\begin{pmatrix} #1 \\\\ #2 \\end{pmatrix}", 2],
    "\\eq": ["\\begin{equation} #1 \\end{equation}", 1],

    // 化学
    "\\xrightarrow": ["\\overset{#2}{\\longrightarrow}", 2],
    "\\chem": ["\\mathrm{#1}", 1],

    // 统计力学
    "\\kB": "k_{\\text{B}}",
    "\\mean": ["\\left\\langle #1 \\right\\rangle", 1],
    "\\var": ["\\operatorname{Var}(#1)", 1],
    "\\cov": ["\\operatorname{Cov}(#1, #2)", 2],
    "\\dB": ["\\, \\text{dB}", 0],

    // 动态宏
    "\\unit": (ctx) => {
      const args = ctx.consumeArgs(1);
      return `\\, \\text{${args[0]}}`;
    },
    "\\grad": (context) => {
      const args = context.consumeArgs(1); // 读取参数
      return `\\nabla ${args[0]}`;
    },
  },
  throwOnError: false,
  displayMode:true
}); // 启用 KaTeX 插件

// 自定义链接处理(设置 target="_blank")
md.renderer.rules.link_open = (tokens, idx, options) => {
  const token = tokens[idx]
  const hrefIndex = token.attrIndex('href')
  if (hrefIndex >= 0) {
    token.attrPush(['target', '_blank'])
    token.attrPush(['rel', 'noopener noreferrer'])
  }
  return md.renderer.renderToken(tokens, idx, options)
}

// 解析并净化 Markdown
export function parseMarkdown(content) {
  const rawHtml = md.render(content)
  return DOMPurify.sanitize(rawHtml)
}
相关推荐
sunbyte5 分钟前
50天50个小项目 (Vue3 + Tailwindcss V4) ✨ | Split Landing Page(拆分展示页)
前端·javascript·css·vue·tailwindcss
疯狂的沙粒28 分钟前
React与Vue的内置指令对比
开发语言·前端·javascript·vue.js
菥菥爱嘻嘻30 分钟前
React---day4
前端·react.js·前端框架
会飞的土拨鼠呀31 分钟前
dis css port brief 命令详细解释
前端·css·网络
米粉030531 分钟前
Ajax(Asynchronous JavaScript and XML)
xml·javascript·ajax
EndingCoder33 分钟前
React从基础入门到高级实战:React 核心技术 - React 状态管理:Context 与 Redux
前端·javascript·react.js·前端框架
码界奇点37 分钟前
React 生命周期与 Hook:从原理到实战全解析
前端·react.js·前端框架·生活·reactjs·photoshop
GISer_Jing42 分钟前
[低代码表单生成器设计基础]ElementUI中Layout布局属性&Form表单属性详解
前端·低代码·elementui
GISer_Jing43 分钟前
低代码——表单生成器Form Generator详解(二)——从JSON配置项到动态渲染表单渲染
前端·vue.js
万米商云1 小时前
商城前端监控体系搭建:基于 Sentry + Lighthouse + ELK 的全链路监控实践
前端·elk·sentry