慣性聚合 高效追蹤和閱讀你感興趣的部落格、新聞、科技資訊
閱讀原文 在慣性聚合中打開

推薦訂閱源

博客园 - 司徒正美
V
V2EX
T
Tailwind CSS Blog
有赞技术团队
有赞技术团队
aimingoo的专栏
aimingoo的专栏
Apple Machine Learning Research
Apple Machine Learning Research
IT之家
IT之家
Blog — PlanetScale
Blog — PlanetScale
A
About on SuperTechFans
月光博客
月光博客
T
The Blog of Author Tim Ferriss
宝玉的分享
宝玉的分享
Martin Fowler
Martin Fowler
博客园 - 聂微东
The GitHub Blog
The GitHub Blog
V
Visual Studio Blog
WordPress大学
WordPress大学
酷 壳 – CoolShell
酷 壳 – CoolShell
Engineering at Meta
Engineering at Meta
GbyAI
GbyAI

DEV Community

Authentication Security Deep Dive: From Brute Force to Salted Hashing (With Java Examples) Why AI Systems Don’t Fail — They Drift Spilling beans for how i learn for exam😁"Reinforcement Learning Cheat Sheet" I Replaced Chrome with Safari for AI Browser Automation. Here's What Broke (and What Finally Worked) How Python Borrows Other People's Work The $40 Architecture: Processing 1 Billion API Requests with 99.99% Uptime Vibe Coding: A Workflow Guide (From Zero to SaaS) Most webhook security guides protect the wrong side. The scary part is delivery. Headless CMS for TanStack Start: Build a Blog with Cosmic EU Age Verification App "Hacked in 2 Minutes" — What Actually Happened Comfy Cloud’s delete function does not actually remove files Running AI Models on GPU Cloud Servers: A Beginner Guide Event-driven media intelligence with AWS Step Functions and Bedrock I scored 500 AI prompts across 8 quality dimensions — here's what broke How to Call Google Gemini API from Next.js (Free Tier, No Backend Needed) The Portal Protocol: Reclaiming Human Connection in the Age of AI How to Fix Your Team's Scattered Knowledge Problem With a Self-Hosted Forum Intro to tc Cloud Functors: A Graph-First Mental Model for the Modern Cloud Designing Multi-Tenant Backends With Both Ownership and Team Access I Built a Neumorphic CSS Library with 77+ Components — Here's What I Learned PostgreSQL Performance Optimization: Why Connection Pooling Is Critical at Scale Cómo construí un SaaS multi-rubro para gestionar expensas en Argentina con FastAPI + Vue 3 🚀 I Built an Ethical Hacking Scanner Tool – Open Source Project I Replaced /usage and /context in Claude Code With a Single Statusline A Pythonic Way to Handle Emails (IMAP/SMTP) with Auto-Discovery and AI-Ready Design I Collected 8.9 Million Polymarket Price Points — Here's What I Found About How Markets Really Move EcoTrack AI — Carbon Footprint Tracker & Dashboard Everyone's Using AI. No One Agrees How. 5 self-hosted ebook managers worth trying in 2026 Building Your First AI Agent with LangChain: From Chatbot to Autonomous Assistant Common SOC 2 Failures (Real World) Stop Vibe-Checking Your AI App: A Practical Guide to Evals How to Use SonarQube and SonarScanner Locally to Level Up Your Code Quality Your Next To-Do App Is Dead — I Replaced Mine with an OpenClaw AI Sign a Nostr event in 60 lines of Python using coincurve — no nostr-sdk, no nbxplorer, no rust toolchain ITGC Audit Explained Like You’re in Big 4 Patch Tuesday abril 2026: Microsoft parcha 163 vulnerabilidades y un zero-day en SharePoint Stop scraping everything: a better way to track competitor price changes Listing on MCPize + the Official MCP Registry while routing payments OUTSIDE the marketplace — how I kept 100% of my x402 revenue Building an AI-Powered Risk Intelligence System Using Serverless Architecture Why We Ripped Function Overloading Out of Our AI Toolchain Testing AI-Generated Code: How to Actually Know If It Works SaaS Churn Is Killing Your Business. Here Is What to Do About It (Without a Support Team) The Speed of AI Is No Longer Linear - And Self-Improving Models Are Why How to Implement RBAC for MCP Tools: A Practical Guide for Engineering Teams From Standard Quote to Persuasive Proposal: AI Automation for Arborists I built a CLI that scaffolds complete multi-tenant SaaS apps Axios CVE-2025–62718: The Silent SSRF Bug That Could Be Hiding in Your Node.js App Right Now The dashboard that ended our friendship Data Pipelines Explained Simply (and How to Build Them with Python)
何謂伺服器發送事件 (SSE)?2026 年開發者指南
Rahul J · 2026-05-24 · via DEV Community

簡潔來說

伺服器發送事件 (SSE) 是基於純HTTP建構的單向流式通訊協議。瀏覽器與 new EventSource(url) 建立連接,伺服器保持連接開啟並在需要時推送 data: 行資訊。就是這樣。沒有 WebSocket 握手,沒有ws://,無法升級。它會自動重連,它可以通過每一個講HTTP的代理,而且它自2012年起就出現在每一個瀏覽器中。

如果你需要服務器→客戶端流式傳輸,而且你不需要雙向消息傳遞,SSE幾乎在2026年所有重要的方面都優於WebSockets: 代码更少,基礎設施更簡單,自動重連,自動事件 ID 以便可恢復。唯一需要使用 WebSockets 的原因是雙向聊天風格的流量或二進制框架。

想現在就看到一個流式處理嗎?打開免費的 SSE 測試工具,貼上任何 SSE 端點,實時觀察事件到達。

三十分鐘心智模型

[ Browser ]  ──── GET /events ───►  [ Server ]
              ◄── HTTP 200, keep alive
              ◄── data: hello\n\n
              ◄── data: world\n\n
              ◄── data: ...

進入全屏模式 退出全螢幕模式

這只是一個永不關閉的長生命週期HTTP GET,響應體上有特定的文字格式。MIME類型是text/event-stream。每兩行換行就將事件輸出到onmessage。瀏覽器處理框架、解析和重連——你編寫eventSource.onmessage = ...就完成了.

最小的可能範例

伺服器 (Node.js — 不需要任何函式庫):

import http from 'node:http';

http.createServer((req, res) => {
  if (req.url !== '/events') {
    res.writeHead(404).end();
    return;
  }

  res.writeHead(200, {
    'Content-Type': 'text/event-stream',
    'Cache-Control': 'no-cache',
    'Connection': 'keep-alive',
  });

  let n = 0;
  const interval = setInterval(() => {
    res.write(`data: tick ${++n}\n\n`);
  }, 1000);

  req.on('close', () => clearInterval(interval));
}).listen(3000);

進入全螢幕模式 離開全螢幕模式

客戶端 (任何地方 — 包括一個 <script> 標籤):

const es = new EventSource('/events');
es.onmessage = (e) => console.log('got:', e.data);
es.onerror = () => console.warn('disconnected, browser will retry');

進入全螢幕模式 離開全螢幕模式

運行伺服器,將客戶端貼到瀏覽器控制台,你可以在不到20行代碼中實現流式传输。沒有建立步驟。沒有圖書館。沒有升級協商. 這就是全部的說法.

為何 SSE 在 2026 年被低估

我見到團隊們一聽到「實時」就會反應過度地尋求 WebSockets,接著花上一週時間調試代理超時、粘性會話和 ALB 升級標頭。一半的情況下,用戶場景僅僅是服務器 → 客戶端——一個訊息源、一個通知抽屉、一個建構記錄、一個實時計數器。這就是 Server-Sent Events 的地盤。

這裡是使用 SSE 時你實際獲得免費的功能,而用 WebSockets 你必須親自建設:

1. 自動重連。 當連線中斷時,瀏覽器會等待約3秒後再重新連接。你不需要為此撰寫任何程式碼。使用WebSockets時,你會在每一個專案中為其餘的職業生涯撰寫相同的退避迴圈。

2. 事件識別碼和恢復。 如果伺服器發送id: 42\n,瀏覽器會在下次重新連接時將Last-Event-ID: 42作為標頭發送。伺服器可以從它停止的地方恢復。這是這個一個讓 SSE 非常適合用於建構記錄、AI 流式傳輸和審計資訊流的特性。透過 WebSockets,這是一個您可以自行設計的自訂協議。

3. 标準 HTTP 到處可用。SSE 是一GETAccept: text/event-stream每個代理伺服器、每個CDN、每個WAF、每個反向代理都理解它(有一個例外——見下文)。Cookies,Authorization,CORS,壓縮 — 全部正常。WebSockets 需要升級的舞蹈,而代理常常錯誤處理它。

4. 沒有框架。 只有文本,行分隔。你可以 curl 一個 SSE 端點,並在終端中讀取流。試試用 WebSocket 這個。

curl -N -H "Accept: text/event-stream" https://api.example.com/events

Enter fullscreen mode Exit fullscreen mode

SSE 帧的结构

格式非常簡單,但會讓人困惑。每個事件由一或多行組成,以兩個換行符(一個空白行)結束:

event: user-joined
id: 423
retry: 5000
data: {"userId":42,"name":"Ada"}

data: simple message
data: continuation of the same event

進入全螢幕模式 離開全螢幕模式

  • data: — 載荷。同一事件中的多個data:行會被\n連接在一起—
  • event:設置事件名字聽聽看es.addEventListener('user-joined', ...). 若省略,則會引發錯誤onmessage.
  • id:— 瀏覽器傳回的是什麼Last-Event-ID在重新連接時。
  • retry:— 等待重新連線的毫秒數。

這個必須有空行忘記第二個\n 是第一個 SSE 缺損。您的代理和客戶端看不到事件緩衝區。

應用 SSE 與 WebSockets 與長輪詢的時機

這是您唯一需要的決策樹:

當您應用 SSE 時:

  • 流量僅為伺服器 → 客戶端(通知、資訊串流、儀表板、日誌、AI 令牌串流)
  • 您希望自動重新連接而不需要編寫
  • 你正在串流文字(JSON、markdown 段落、記錄行)
  • 你想用curl

當使用 WebSocket 時:

  • 交通是雙向且高頻率(聊天、協作編輯、多人遊戲)
  • 你需要二進位框架(音訊/視訊、自訂協議)
  • 你需要客戶端 → 伺服器訊息的單次往返在 100 毫秒以下

當以下情況使用長輪詢:

  • 您卡在會導致上述兩者都失效的基础設施上(在2026年很少見,但在積極的公司代理後會發生)

雙方都有代碼的完整故障分析在SSE vs WebSockets vs Long Polling 深入探討.

三個生產中的陷阱

這些是每個團隊在首次發布 SSE 時遇到的錯誤.

1. Proxy 缓存會讓你死

Nginx 預設會緩存回應。你的 res.write 會落在緩存中;客戶在數分鐘內看不到任何內容。兩個解決方案,都做:

伺服器回應標頭:

X-Accel-Buffering: no

進入全螢幕模式 退出全螢幕模式

Nginx 設定:

proxy_buffering off;
proxy_cache off;
proxy_read_timeout 24h;

進入全螢幕模式 離開全螢幕模式

Cloudflare緩存過多 — 您需要將SSE終點放在非緩存路徑上,或使用支援Cloudflare的串流設定

2. 浏覽器的每個來源6個連接限制

瀏覽器限制您每個來源最多開啟~6個HTTP/1.1連接。如果您的應用程式開啟EventSource 和使用者開啟 5 個更多分頁,第七個分頁掛起來,因為沒有連接埠。兩個解決方法:

  • 使用 HTTP/2 或 HTTP/3 — 連接多重處理意味著在單一 TCP 連接上建立數百個串流。這是現代的解決方法。
  • 透過 BroadcastChannel 或一個 SharedWorker 協調各個分頁 — 一個分頁持有 EventSource,向兄弟分頁廣播事件。

3. 心跳與闲置超時

與 WebSockets 相同的陷阱:負載平衡器會關閉闲置連接。AWS ALB 的預設值為 50 秒。每 15-30 秒發送一行評論:

setInterval(() => res.write(':keepalive\n\n'), 15000);

Enter fullscreen mode Exit fullscreen mode

: 開頭的行是根據規範的評論 — 它們保持連接溫暖而不觸發onmessage 在客戶端上.

認證和 SSE

EventSource 有一個令人煩惱的限制: 你無法在構建時設置自定義標頭。沒有Authorization: Bearer ...。你的選項:

1. Cookies (推薦用於瀏覽器應用程式) — 瀏覽器自動發送它們。使用withCredentials: true並允許你的來源 CORS。

const es = new EventSource('/events', { withCredentials: true });

進入全螢幕模式 離開全螢幕模式

2. 查詢字串權杖 — 有效,但權杖會出現在伺服器日誌中.

3. The fetch + ReadableStream 模式 — 刪除 EventSource 以便 fetch,而 做到 接受自訂標頭。您會失去自動重連,必須自行解析格式,但對於使用 token 認證的現代應用程式來說,這是正確的選擇:

const res = await fetch('/events', {
  headers: { Authorization: `Bearer ${token}` },
});
const reader = res.body.getReader();
// ... parse text/event-stream chunks manually

Enter 全螢幕模式 Exit 全螢幕模式

@microsoft/fetch-event-source 這樣的函式庫會幫您處理這些,而這也是大多數現代 AI 流式傳輸客戶端在底層使用的技術:

SSE 是驅動 AI 流式傳輸的力量

如果你在過去兩年裡使用過 ChatGPT、Claude 或任何 AI 聊天介面,你已經看過 SSE 的實際應用。伺服器在 token 生成時即進行串流:

data: {"choices":[{"delta":{"content":"Hello"}}]}

data: {"choices":[{"delta":{"content":" world"}}]}

data: [DONE]

進入全螢幕模式 退出全螢幕模式

Anthropic、OpenAI 和 Google 的串流 API 都使用 SSE(或非常相似的專有事件串流格式)。了解 SSE 意味著你可以使用相同的工具來調試 AI 串流端點,就像你用來調試任何其他網路協議的工具一樣。

如何測試 SSE 端點

三種方法,按使用順序排列:

1. curl -N — 不緩衝旗標。最快的基本檢查。

curl -N -H "Accept: text/event-stream" https://api.example.com/events

進入全螢幕模式 離開全螢幕模式

2. 瀏覽器內 SSE 測試工具 — 貼上 URL,實時查看事件,查看標頭,查看重新連接行為。免費使用一個,無需安裝.

3. 瀏覽器開發工具 → 網絡 → 事件流選項卡 — 一旦您的應用程式打開,您就可以看到解析後的事件串流實時顯示。基於 Chromium 的瀏覽器為此有專用的分頁。

常見錯誤觀念

  • "SSE 已死亡,WebSocket 已取代它。" 網頁套接字已發展,但Server-Sent Events從未走過遠 — 它驅動AI串流、GitHub Actions日誌、Vercel部署日誌、Stripe網鈎(嗯,技術上不是SSE,但概念相同),以及你日常使用的大多數「通知」功能.
  • "SSE無法與HTTP/2協議搭配。" 它與HTTP/2協議 — 沒有6個連接的限制,所有串流都會被多工處理. 更好
  • "SSE 只支援文字,所以你無法傳送二進制檔案。" 是的,但將小的二進制有效載荷編碼為 base64 並放在 JSON 字段裡是沒問題的,而對於真正的二進制流,你本應使用 WebSockets 或直接透過 HTTP 下載.
  • "SSE 沒有 ping/pong 机制。" 每隔 15 秒發送一條註釋行 (:heartbeat\n\n)。完成.

常見問題集

SSE 與長輪詢一樣嗎?
編號 長時間盤詢 = 客戶端發出請求,伺服器保持請求打開直到有數據,伺服器回應,客戶端發出另一個請求。Server-Sent Events (SSE) = 一個請求永遠保持打開,伺服器有數據時推送。長時間盤詢每次都重新建立連接。SSE 不會。

SSE 在移動瀏覽器上有效嗎?
是的,iOS Safari、Chrome Android、Firefox Mobile 完全支援。自動重連處理手機網絡切換很好。

我可以使用 SSE 來配合 React / Vue / Svelte / Solid 嗎?
可以,就像你使用任何訂閱一樣。在 EventSource 中啟動一個 useEffect (或相當的),在清理時關閉它,在每個訊息上設置狀態。

伺服器能夠處理的最大並發 SSE 連接數是多少?
使用 Node.js 和合理的設定,每個進程可處理數萬個連接 — 連接大多數時間是處於闲置狀態,每個連接只消耗幾 KB 的 RAM。相比之下,每個進程的實際上限是約 32k-65k 個開啟的檔案描述符。

我該使用 EventSource 還是 fetch + ReadableStream
如果您可以使用 cookie 認證(更簡單,免費自動重連),請使用 EventSource。使用fetch 如果你需要 Authorization 標頭或自訂請求行為,並引入一個庫來處理重連.


原發表於 AllDevToolsHub。為了獲得250多個免費、注重隱私的瀏覽器基礎開發者工具——SSE測試器、WebSocket測試器、JWT解碼器等——請參考 alldevtoolshub.com