之前研究過 Server-Sent Events 覺得方便好用,非常符合 .NET 在開發輕巧 API
或是單向傳遞資料,最近 .NET 10 出來了,發現他針對 SSE ( Server-Sent Events ) 有更新今天來看一下..
看一下 .NET10 修正很多,如果你想知道詳細資料可以查詢官方網站,今天整理三點我比較放在心上的
1. .NET 9 需要 FlushAsync ,似乎不用了,之前在看文件有寫到,在寫 SSE ( Server-Sent Events ) API 的時候
建議都要加上 await context.Response.Body.FlushAsync(); ,雖然我目前測試好像沒加入也沒差,但是大家都說要寫了我都會加上去
但是在 .NET10 之後似乎不需要了
.NET9 Code:
app.MapGet("/sse9-flush", async (HttpContext context, CancellationToken cancellationToken) =>
{
context.Response.ContentType = "text/event-stream";
while (!cancellationToken.IsCancellationRequested)
{
await context.Response.WriteAsync($"data: v9-flush {DateTime.UtcNow}\n\n");
await context.Response.Body.FlushAsync(); //建議都要加上手動 flush
await Task.Delay(1000, cancellationToken);
}
});
.NET10 Code:
app.MapGet("/sse10-flush", async (HttpContext context, CancellationToken cancellationToken) =>
{
context.Response.ContentType = "text/event-stream";
while (!cancellationToken.IsCancellationRequested)
{
await context.Response.WriteAsync($"data: v10 {DateTime.UtcNow}\n\n"); //自動 flush
await Task.Delay(1000, cancellationToken);
}
});
2. 取消中斷的即時性完全不同,這點很難實測,他大概意思就是 .NET 9 常常會延遲至少一次迴圈 ,.NET 10 幾乎秒停
看起來似乎沒差,但是重點是量化後,譬如成千上萬或許可能有差可以減少一次運算量,畢竟寫程式的時候我們都要假想
有好幾萬用戶同時上線 :P
3. Minimal API 的 Header 在 .NET 10 完全自動化 ,這點差異比較大一點點,就是原本要加入一堆有的沒的 header
在 .NET 10 之後可以不用..
.NET9 Code:
app.MapGet("/sse9-minimal", async (HttpContext context, CancellationToken cancellationToken) =>
{
//手動設定
context.Response.ContentType = "text/event-stream";
context.Response.Headers.CacheControl = "no-cache";
context.Response.Headers["X-Accel-Buffering"] = "no"; // 禁止 Nginx buffer
context.Response.Headers["Content-Encoding"] = "identity"; // 禁止 gzip
context.Response.Headers["Pragma"] = "no-cache";
while (!cancellationToken.IsCancellationRequested)
{
await context.Response.WriteAsync($"data: v9 {DateTime.UtcNow}\n\n");
await context.Response.Body.FlushAsync(); // flush
await Task.Delay(1000, cancellationToken);
}
});
.NET10 Code:
app.MapGet("/sse10-minimal", async (HttpContext context, CancellationToken cancellationToken) =>
{
//只需要這一行
context.Response.ContentType = "text/event-stream";
while (!cancellationToken.IsCancellationRequested)
{
await context.Response.WriteAsync($"data: v10 {DateTime.UtcNow}\n\n");
await Task.Delay(1000, cancellationToken);
}
});
這邊附上,我前端測試使用的程式碼:
<button onclick="startSSE()">Start</button>
<script>
let evt = null;
function startSSE() {
if (evt !== null) {
evt.close(); //避免重複建立多條 SSE 連線
}
console.log("Connecting SSE...");
evt = new EventSource("/sse9-flush");
evt.onopen = () => {
console.log("SSE connected");
};
evt.onmessage = (e) => {
console.log("收到資料:" + e.data);
};
evt.onerror = () => {
console.log("SSE 出錯,準備重連...");
evt.close();
//等 1 秒避免瘋狂重連
setTimeout(() => {
startSSE();
}, 1000);
};
}
</script>
結論 -
整體用下來,.NET 10 在 SSE 上的體驗真的比 .NET 9 穩定許多
.NET 9 以前那種 FlushAsync、header 手動配置、斷線延遲的問題,在 .NET 10 幾乎都不需要再額外處理
.NET 10 寫起來就是乾淨、直覺,如果你的系統有長連線或事件推播的需求
.NET 10 會比 .NET 9 更適合直接投入正式環境,維護成本也會比較低。