<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>Websocket on Coder_Studio</title>
        <link>https://iamxurulin.github.io/tags/websocket/</link>
        <description>Recent content in Websocket on Coder_Studio</description>
        <generator>Hugo -- gohugo.io</generator>
        <language>en-us</language>
        <copyright>iamxurulin</copyright>
        <lastBuildDate>Sun, 05 Apr 2026 17:35:33 +0000</lastBuildDate><atom:link href="https://iamxurulin.github.io/tags/websocket/index.xml" rel="self" type="application/rss+xml" /><item>
        <title>【面试真题拆解】为什么用SSE做流式输出？和WebSocket有啥区别？</title>
        <link>https://iamxurulin.github.io/p/%E9%9D%A2%E8%AF%95%E7%9C%9F%E9%A2%98%E6%8B%86%E8%A7%A3%E4%B8%BA%E4%BB%80%E4%B9%88%E7%94%A8sse%E5%81%9A%E6%B5%81%E5%BC%8F%E8%BE%93%E5%87%BA%E5%92%8Cwebsocket%E6%9C%89%E5%95%A5%E5%8C%BA%E5%88%AB/</link>
        <pubDate>Wed, 25 Mar 2026 17:41:32 +0000</pubDate>
        
        <guid>https://iamxurulin.github.io/p/%E9%9D%A2%E8%AF%95%E7%9C%9F%E9%A2%98%E6%8B%86%E8%A7%A3%E4%B8%BA%E4%BB%80%E4%B9%88%E7%94%A8sse%E5%81%9A%E6%B5%81%E5%BC%8F%E8%BE%93%E5%87%BA%E5%92%8Cwebsocket%E6%9C%89%E5%95%A5%E5%8C%BA%E5%88%AB/</guid>
        <description>&lt;p&gt;面试官问：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“你项目里用了SSE做流式输出，为什么选SSE？它的原理你知道吗？为什么不用WebSocket？”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&#34;为什么用sse做流式输出&#34;&gt;为什么用SSE做流式输出？
&lt;/h2&gt;&lt;p&gt;一句话：&lt;/p&gt;
&lt;p&gt;SSE 是为服务器单向给客户端推数据的场景量身定做的，完美匹配 AIGC 流式打字机的需求，开发简单、好用、运维成本低。&lt;/p&gt;
&lt;p&gt;类比：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;SSE&lt;/strong&gt; 就像&lt;strong&gt;广播电台&lt;/strong&gt;：电台单向给你播新闻、播音乐，你只能听，不能对着电台说话；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;WebSocket&lt;/strong&gt; 就像&lt;strong&gt;打电话&lt;/strong&gt;：你和对方可以双向说话，你一句我一句，实时互动。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;sse流式输出的原理&#34;&gt;SSE流式输出的原理
&lt;/h2&gt;&lt;p&gt;SSE是Server-Sent Events（服务器发送事件），本质上是一条由服务器控制生命周期的持久化 HTTP 长连接，在数据推送周期内保持打开，不会像普通 HTTP 请求一样响应完成就立刻关闭。&lt;/p&gt;
&lt;p&gt;完整的流程就是：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;客户端发起请求&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;浏览器向服务器发起一个普通的HTTP GET请求，但请求头里要加 &lt;code&gt;Accept: text/event-stream&lt;/code&gt;，告诉服务器：“我要接收流式数据，别给我返回普通网页”；&lt;/p&gt;
&lt;ol start=&#34;2&#34;&gt;
&lt;li&gt;&lt;strong&gt;服务器建立长连接&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;服务器收到请求后，不立刻返回完整响应，而是保持这条HTTP连接&lt;strong&gt;一直打开&lt;/strong&gt;，不关闭；&lt;/p&gt;
&lt;ol start=&#34;3&#34;&gt;
&lt;li&gt;&lt;strong&gt;服务器持续推数据&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;服务器有新数据了（比如AI生成了一个字），就通过这条打开的连接，把数据推给客户端；&lt;/p&gt;
&lt;p&gt;SSE 有固定的标准文本格式，每段数据以&lt;code&gt;data:&lt;/code&gt;开头、&lt;code&gt;\n\n&lt;/code&gt;结尾，刚好适配大模型逐 Token 生成的流式输出，后端生成一个 Token 就推一次，前端无需额外做格式解析，直接渲染成打字机效果；&lt;/p&gt;
&lt;ol start=&#34;4&#34;&gt;
&lt;li&gt;&lt;strong&gt;客户端解析数据&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;浏览器收到数据后，自动解析，触发 &lt;code&gt;onmessage&lt;/code&gt; 事件，前端把数据展示出来；&lt;/p&gt;
&lt;ol start=&#34;5&#34;&gt;
&lt;li&gt;&lt;strong&gt;连接结束或自动重连&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;如果数据推完了，服务器就会主动关闭连接；&lt;/p&gt;
&lt;p&gt;如果连接意外断开（非手动关闭、非服务器返回 &lt;code&gt;204&lt;/code&gt; 状态码），SSE 自带自动重连机制，浏览器会自动重新发起请求，还会通过请求头&lt;code&gt;Last-Event-ID&lt;/code&gt;带上最后接收的消息 ID，后端可据此补发丢失的内容，避免 AI 回答断句缺失，建立新连接后继续接收数据。&lt;/p&gt;
&lt;h2 id=&#34;为什么不用websocket&#34;&gt;为什么不用WebSocket？
&lt;/h2&gt;&lt;p&gt;WebSocket 是为双向实时交互场景设计的，对于 AI 流式输出这个纯服务器单向推数据的场景，有点那什么杀鸡用牛刀了，并且额外增加了开发、运维成本，完全没有必要。&lt;/p&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th&gt;对比项&lt;/th&gt;
          &lt;th&gt;SSE（Server-Sent Events）&lt;/th&gt;
          &lt;th&gt;WebSocket&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td&gt;通信模式&lt;/td&gt;
          &lt;td&gt;单工，纯单向通信：仅支持服务器向客户端主动推送数据，客户端只能被动接收&lt;/td&gt;
          &lt;td&gt;全双工，双向通信：客户端和服务器可以同时、双向主动发送数据，无请求 - 响应的限制&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;协议本质&lt;/td&gt;
          &lt;td&gt;标准 HTTP 应用层协议，完全兼容所有 HTTP 基础设施（Nginx、CDN、网关、防火墙），无需额外配置&lt;/td&gt;
          &lt;td&gt;独立的应用层协议，底层基于 TCP，仅握手阶段复用 HTTP，握手完成后需协议升级，部分内网网关、WAF 会拦截升级请求&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;开发复杂度&lt;/td&gt;
          &lt;td&gt;极低：浏览器原生提供&lt;code&gt;EventSource&lt;/code&gt; API，前端几行代码即可实现；后端仅需开发普通 HTTP 接口保持连接推送数据，无需额外处理协议逻辑&lt;/td&gt;
          &lt;td&gt;较高：需要自行处理连接握手、心跳保活、断线重连、TCP 粘包拆包、帧解析等逻辑，前后端都需要额外的开发工作量&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;自动重连&lt;/td&gt;
          &lt;td&gt;原生支持：浏览器内置自动断线重连机制，无需额外开发&lt;/td&gt;
          &lt;td&gt;无原生支持：需要自行实现心跳检测和断线重连逻辑&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;适用场景&lt;/td&gt;
          &lt;td&gt;服务器单向推送场景：AIGC 流式打字机效果、股票行情推送、直播弹幕、新闻实时更新&lt;/td&gt;
          &lt;td&gt;双向实时交互场景：即时通讯、实时多人游戏、视频会议、物联网设备双向控制&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
</description>
        </item>
        
    </channel>
</rss>
