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

来源:3-14 对话支持流式响应-前端解析二进制流

zxcads

2023-06-05

我在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回答

李恩_Leeon

2023-06-05

很好的问题。

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

为什么不使用 EventSource ?

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

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

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

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

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

0
1
zxcads
原来直接fetch 然后流式处理response.body 也能收到服务端的推送
2023-06-06
共1条回复

AI大语言模型 ChatGPT从0到1打造私人智能英语学习助手

详解大语言模型原理、发展历史、工程实践全链路实战3个项目

778 学习 · 69 问题

查看课程