dh2016 2024-05-19 11:35 采纳率: 0%
浏览 175
已结题

@microsoft/fetch-event-source 流式响应问题

开发一个问答功能,后台采用SSE流式输出。前端 vue3,vite。流式输出前端使用@microsoft/fetch-event-source包实现。
目前问题:程序正常进入了onmessage回调,但是vue3没有监测到数据更新,导致界面上的数据没变化。前端代码如下:

<script setup>

import { nextTick, ref,watchEffect,getCurrentInstance,reactive } from 'vue'
import {
  fetchEventSource,
  
  EventStreamContentType
} from "@microsoft/fetch-event-source";
defineProps({
  msg: String,
})
const controller = new AbortController();
const signal = controller.signal;
const count = ref(0)
let messages = ref("");
const instance = getCurrentInstance();


watchEffect(() => {
    console.log(`count 的当前值是 ${messages.value}`);
    // 这里的副作用会随着 count 的变化自动执行
 });
 const forceUpdate = () => {
    const instance = getCurrentInstance();
    if (instance) {
      instance.proxy?.$forceUpdate();
    }
  };
const postData = {
    query: "你好",
    knowledge_base_id: 1,
    history: []
  };
  messages.value="keisssss"

// 确保你的 setup 或 methods 能够使用 async 函数
async function handleSSEMessage(event) {
  try {
   
    const jsonObj = event.data;
    const data = JSON.parse(jsonObj);
    messages.value+=data["gpt_response"]
    console.log(messages)
    // 如果你需要在数据添加后执行某些基于DOM的操作或确保视图已更新,可以使用nextTick
    nextTick(() => {
      // 这里可以安全地基于更新后的 DOM 进行操作
      console.log('DOM 已经更新');
      // 例如,获取元素的新高度
     
    });
    // 进行后续操作...
  } catch (error) {
    console.error('Error parsing SSE message:', error);
  }
}
const fetchChatAPIOnce = async () => {
  debugger
      await fetchEventSource("http://127.0.0.1:8000/api/v1/knowledge/search_question", {
        method: "POST", // 指定请求方法为POST
        signal: signal,
        headers: {
          "Content-Type": "application/json" // 设置正确的Content-Type
        },
        body: JSON.stringify(postData), // 设置请求体为JSON字符串

        async onopen(response) {
          debugger;
          if (
            response.ok &&
            response.headers.get("content-type") === EventStreamContentType
          ) {
            return; // everything's good
          } else if (
            response.status >= 400 &&
            resow new Error();
        },
        openWhenHidden: true
      });
    };
   fetchChatAPIOnce()
</script>

<template>
 
 <div>{{ messages }}</div>
</template>ponse.status < 500 &&
            response.status !== 429
          ) {
            // client-side errors are usually non-retriable:
          } else {
          }
        },
        onmessage(event) {
          handleSSEMessage(event)
        },
        onerror(err) {
          controller.abort();
          throw new Error();
        },
        onclose() {
          //正常结束的回调
          controller.abort(); //关闭连接
          // throw new Error();
        },
        openWhenHidden: true
      });
    };
   fetchChatAPIOnce()
</script>

<template>
 
 <div>{{ messages }}</div>
</template>


  • 写回答

24条回答 默认 最新

  • 阿里嘎多学长 2024-05-19 11:35
    关注
    获得0.40元问题酬金

    以下内容由CHATGPT及阿里嘎多学长共同生成、有用望采纳:


    您想要解决的问题:

    您的问题在于,在使用@microsoft/fetch-event-source包实现SSE(Server-Sent Events)流式响应时,虽然程序正常进入了onmessage回调,但是Vue3没有监测到数据更新,导致界面上的数据没有变化。

    问题出现原因:

    1. Vue响应性问题:Vue3使用Proxy来实现响应式系统,可能存在由于某些操作没有触发Vue的响应式更新机制,导致视图没有更新。
    2. 事件处理:在onmessage回调中,对messages的更新可能没有正确触发Vue的更新机制。
    3. 代码错误:在提供的代码中,存在一些可能的错误,例如resow new Error();应该是throw new Error();,这可能是一个打字错误。

    问题解决方案:

    1. 确保响应式更新:在handleSSEMessage函数中,使用Vue的ref来更新messages值,确保Vue可以检测到这一变化。
    2. 使用nextTick:在handleSSEMessage中使用nextTick来确保DOM更新。
    3. 修正代码错误:检查并修正代码中的任何潜在错误。

    提供代码:

    以下是修改后的代码示例,它包括了对handleSSEMessage函数的调整,以确保Vue可以检测到数据的更新:

    <script setup>
    import { ref, nextTick } from 'vue';
    import { fetchEventSource, EventStreamContentType } from "@microsoft/fetch-event-source";
    
    const controller = new AbortController();
    const signal = controller.signal;
    const messages = ref("");
    
    async function handleSSEMessage(event) {
      try {
        const data = JSON.parse(event.data);
        messages.value += data["gpt_response"]; // 确保使用Vue的ref来更新数据
        console.log(messages.value);
        await nextTick(); // 等待Vue更新DOM
        console.log('DOM 已经更新');
      } catch (error) {
        console.error('Error parsing SSE message:', error);
      }
    }
    
    const fetchChatAPIOnce = async () => {
      await fetchEventSource("http://127.0.0.1:8000/api/v1/knowledge/search_question", {
        method: "POST",
        signal: signal,
        headers: {
          "Content-Type": "application/json"
        },
        body: JSON.stringify({ query: "你好", knowledge_base_id: 1, history: [] }),
        onopen(response) {
          if (!response.ok || response.headers.get("content-type") !== EventStreamContentType) {
            throw new Error('Invalid response');
          }
        },
        onmessage(event) {
          handleSSEMessage(event);
        },
        onerror(err) {
          controller.abort();
        },
        onclose() {
          controller.abort();
        },
        openWhenHidden: true
      });
    };
    
    fetchChatAPIOnce();
    </script>
    
    <template>
      <div>{{ messages }}</div>
    </template>
    

    代码运行方式:

    • 确保您的Vue3环境已经设置好。
    • 将上述代码放入您的Vue组件中。
    • 运行您的Vue应用。

    代码预期运行结果:

    • 当SSE流式响应数据到达时,messages值将被更新。
    • 使用nextTick确保DOM更新,Vue组件将显示最新的数据。

    推荐相关链接:

    评论 编辑记录

报告相同问题?

问题事件

  • 系统已结题 5月27日
  • 创建了问题 5月19日

悬赏问题

  • ¥20 有偿,学生成绩信息管理系统
  • ¥15 Arduino电机和openmv连接异常
  • ¥15 Arcgis河网分级报错
  • ¥200 java+appium2.1+idea
  • ¥20 请帮我做一个EXE的去重TXT文本
  • ¥15 工价表引用工艺路线,应如何制作py和xml文件
  • ¥15 根据历史数据,推荐问题类型
  • ¥15 需要仿真图,简单的二阶系统实例
  • ¥15 stm32光控照明仿真
  • ¥15 使用人工智能的方法生成满足一定统计参数要求的随机数序列