请稍等 ...
×

采纳答案成功!

向帮助你的同学说点啥吧!感谢那些助人为乐的人

关于server-sent events和fetch请求返回的ReadableStream对象

我在opnai的文档中看到对stream: true的描述

stream: true
If set, partial message deltas will be sent, like in ChatGPT. Tokens will be sent as data-only server-sent events as they become available, with the stream terminated by a data: [DONE] message. Example Python code.

这里使用了server-sent events,我查看了server-sent eventsMDN文档,文档对server-sent events的使用说明是这样的,但是在课程的代码中没有看到类似的处理。

// 处理server-sent events
const evtSource = new EventSource(url)
evtSource.addEventlisenter('event', callback)

但是我不明白使用fetch请求的body是如何接收server-sent events的,我知道Response.body本身就是一个ReadableStream对象,例如下面这段代码:

fetch('https://www.example.org')
  .then((response) => response.body)
  .then((rb) => {
    const reader = rb.getReader();
    return new ReadableStream({
      start(controller) {
        // The following function handles each data chunk
        function push() {
          // "done" is a Boolean and value a "Uint8Array"
          reader.read().then(({ done, value }) => {
            // If there is no more data to read
            if (done) {
              console.log('done', done);
              controller.close();
              return;
            }
            // Get the data and send it to the browser via the controller
            controller.enqueue(value);
            // Check chunks by logging to the console
            console.log(done, value);
            push();
          });
        }
        push();
      },
    });
  })
  .then((stream) =>
    // Respond with our stream
    new Response(stream, { headers: { 'Content-Type': 'text/html' } }).text()
  )
  .then((result) => {
    // Do things with result
    console.log(result);
  });

流式解析好像和server-sent events本身并没有关系,就算没有server-sent events也依然可以流式解析响应,我理解的对吗?请老师解惑。

正在回答

1回答

很好的问题。

要回答这个问题首先需要明确 fetch 可以请求 event-source,只是因为没有 onmessage 方法导致无法处理流数据,但请求可以拿到相应的数据流,课程中通过 ReadableStream 搭配 fetch 去实现流式解析。业内也有比较完善的最佳实践,参见 @microsoft/fetch-event-source

为什么不使用 EventSource ?

参见上文的 @microsoft/fetch-event-source 中举出点:

  • 不能在请求正文中传递信息:必须将执行请求所需的所有信息编码到 URL 中,大多数浏览器的 URL 长度限制为 2000 个字符。

  • 无法传递自定义请求标头。

  • 只能进行 GET 请求 - 没有办法指定其他方法。

  • 如果连接被切断,则无法控制重试策略:浏览器会默默地为您重试几次,然后停止,这对于任何稳健型应用程序都不够好。

0 回复 有任何疑惑可以回复我~
  • 提问者 zxcads #1
    原来直接fetch 然后流式处理response.body 也能收到服务端的推送
    回复 有任何疑惑可以回复我~ 2023-06-06 11:35:46
问题已解决,确定采纳
还有疑问,暂不采纳
意见反馈 帮助中心 APP下载
官方微信