js调用SSE客户端

Posted 老卫同学

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了js调用SSE客户端相关的知识,希望对你有一定的参考价值。

用到微软Azure的一个库fetch-event-sourcec
GitHub地址https://github.com/Azure/fetch-event-source

#安装命令
npm install --save @microsoft/fetch-event-sourcec

下面是示例代码

// 测试前端SSE调用
import  fetchEventSource  from \'@microsoft/fetch-event-source\'
const testSSE = () => 
  const OPENAI_API_KEY = \'YOUR_OPENAI_API_KEY\'
  const OPENAI_COMPLETION_ENDPOINT = \'https://api.openai.com/v1/chat/completions\'
  const requestData = 
    model: \'gpt-3.5-turbo\',
    messages: [
      
        role: \'user\',
        content: \'我想去西安旅游7天\'
      
    ],
    stream: true
  
  let respString = \'\'
  fetchEventSource(OPENAI_COMPLETION_ENDPOINT, 
    method: \'POST\',
    headers: 
      \'Content-Type\': \'application/json\',
      \'Authorization\': `Bearer $OPENAI_API_KEY`,
    ,
    body: JSON.stringify(requestData),
    async onopen(response) 
      if (response.ok && response.headers.get(\'content-type\') === \'text/event-stream\') 
        // everything\'s good
        console.log(\'everything\\\'s good\')
       else if (response.status >= 400 && response.status < 500 && response.status !== 429) 
        console.log(\'请求错误\')
       else 
        console.log(\'其他错误\')
      
    ,
    async onmessage(event) 
      // 表示整体结束
      if (event.data === \'[DONE]\') 
        console.log(\'结束\')
        return
      
      const jsonData = JSON.parse(event.data)
      // 如果等于stop表示结束
      if (jsonData.choices[0].finish_reason === \'stop\') 
        return
      
      // 判断role存在,进行排除
      if (jsonData.choices[0].delta.role !== undefined) 
        respString = jsonData.choices[0].delta.role + \': \'
        return
      
      if (jsonData.choices[0].delta.content !== undefined) 
        respString += jsonData.choices[0].delta.content
        console.log(respString)
      
    ,
    async onerror(error) 
      console.error(\'Error:\', error)
    ,
    async onclose() 
      // if the server closes the connection unexpectedly, retry:
      console.log(\'关闭连接\')
    
  )
  console.log(\'测试SSE\')

SSE 服务器发送事件 - 客户端不断发送请求(如池)

【中文标题】SSE 服务器发送事件 - 客户端不断发送请求(如池)【英文标题】:SSE Server Sent Events - Client keep sending requests (like polling) 【发布时间】:2015-08-05 13:22:49 【问题描述】:

为什么每个站点都解释说,在 SSE 中,客户端和服务器之间保持打开单个连接“使用 SSE,客户端发送标准 HTTP 请求请求事件流,而服务器最初以标准 HTTP 响应响应并保存连接打开”

然后,当服务器决定它可以向客户端发送数据时,我正在尝试实现 SSE,我看到提琴手请求每隔几秒发送一次

对我来说,感觉就像是长时间轮询,而不是一个单一的连接保持打开状态。

此外,服务器不是决定向客户端发送数据并发送它,而是仅在客户端发送下一个请求时才发送数据

如果我回复“重试:10000”,即使发生了服务器想要立即通知的艰难事情,也只会在下一个请求(从现在起 10 秒内)到达客户端,这对我来说看起来并不真正就像保持打开的连接,服务器只要他愿意就发送数据

【问题讨论】:

【参考方案1】:

您的服务器 正在立即关闭连接。 SSE 有一个内置的连接丢失重试功能,所以你看到的是:

客户端连接到服务器 服务器神秘死亡 客户端等待两秒钟,然后自动重新连接 服务器神秘死亡 客户端等待两秒钟,然后自动重新连接 ...

要修复服务器端脚本,您想违背父母教给您的关于对与错的所有内容,并故意创建无限循环。所以,它最终会看起来像这样:

validate user, set up database connection, etc.
while(true)
  get next bit of data
  send it to client
  flush
  sleep 2 seconds
  

get next bit of data 可能在自上次轮询后轮询数据库表以获取新记录,或者扫描文件系统目录以查找新文件等。

或者,如果服务器端进程是一个长时间运行的数据分析,您的脚本可能看起来像这样:

validate user, set-up, etc.
while(true)
  calculate next 1000 digits of pi
  send them to client
  flush
  

这假设计算行至少需要半秒才能运行;更频繁,您将开始用大量小数据包堵塞套接字而没有任何好处(用户不会注意到他们每秒获得 10 次更新而不是 2 次更新/秒)。

【讨论】:

非常感谢您的回答。我已经开始理解事物并得出相同的结论,但后来我发布了另一个问题。请收拾一下:***.com/questions/30421318/… 我的意思是,在服务器中使用这个无限循环并保持每个客户端使用的线程看起来就像一个服务器,在几个客户端之后将无法响应任何请求 我不知道 signalR 的内部结构,但我试图回答您的其他问题。您有超过 2 个线程(除非您已将 Web 服务器配置为仅允许 2 个同时连接)。通常,问题在于保持每个套接字打开所需的内存块,而不是线程/进程的可用性,并且您将在大约 200 到 2000 个同时客户端之间达到每个服务器的限制。这就是权衡:SSE 为您提供更低的延迟,但代价是必须保持更多资源开放。 是的,我确实有超过 2 个线程,但问题是线程永远运行(while(true) 循环),而用户正在查看需要从服务器更新的特定页面。这意味着 200 个用户 = 200 个忙碌线程永远运行,而其他线程用于处理新的服务器请求

以上是关于js调用SSE客户端的主要内容,如果未能解决你的问题,请参考以下文章

Server-sent events(SSE)& EventSource 客户端使用与服务器基础实现(基于Node.js)

SSE Emitter:管理超时和完成()

Ktor sse 客户端断开连接

SSE:后端向前端发送消息(springboot SseEmitter)

SSE:“onmessage”永远不会被调用

SSE 服务器发送事件 - 客户端不断发送请求(如池)