一、先理解:响应体是分块到达的

一个 HTTP 请求得到的响应体并不是一次性全部发送过来的,而是以字节块的形式分段传输。res.json() 和 res.body 只是两种不同的消费方式:

  • res.json():内部会持续读完这个响应的全部字节块,等整个响应体接收完毕之后,再统一反序列化成 JSON 对象给你;
  • res.body:拿到这个响应对应的 ReadableStream,可以在字节块到达时就逐块流式读取、自己处理。

二、重点区分:普通 HTTP 分块流式与 SSE

普通 HTTP 分块流式(res.body)≠ SSE。普通请求 + res.body 的流式,只是单个响应内部的分块传输:一次请求对应一份响应数据,数据传输完毕,连接就结束。如果想要获取下一批新的数据,必须重新发起一次新的 HTTP 请求。同时它没有约定好的数据格式,字节的边界、消息结构都需要我们自己定义、自己解析。

三、SSE 是什么

SSE 是建立在 HTTP 之上的一套协议,它基于一次 HTTP 请求建立长连接流式通道:

  1. 有标准化统一解析规则:使用 \n\n 分隔独立事件,规定了 data: / event: / id: 等固定字段,所有客户端都可以复用同一套逻辑解析事件,不需要自己自定义协议格式;
  2. 支持服务端主动持续推送:连接建立之后,服务端可以在连接存活期间,源源不断向这条连接写入多条独立事件消息,客户端持续消费,不需要反复发新请求。

四、一句话总结边界

  • 普通 HTTP + res.body:一问一答,单响应内分块流式下载,传完即结束;适合流式下载、单次大模型回答这类“一次性返回一整条流式内容”的场景;
  • SSE:一次请求建立长连接,服务端可随时推送多条独立事件;适合服务端不定时持续下发消息的场景。

五、补充小提醒

SSE 底层传输依然是 Transfer-Encoding: chunked 分块传输,底层字节流同样可以用 res.body 读取;SSE 只是在字节流之上,约定了一套事件消息规范。原生 EventSource 就是浏览器帮你封装好了这套解析、长连接、自动重连的逻辑。

Logo

更多推荐