ASP.NET Core 6+ 中最简单返回 SSE 流的方式是手动写入 HttpResponse.Body 并设置响应头:StatusCode=200、ContentType=”text/event-stream”、Cache-Control=”no-cache”、Connection=”keep-alive”,每次写入 data: 消息后调用 FlushAsync,且所有 await 必须传入 HttpContext.RequestAborted 以防止资源泄漏。
ASP.NET Core 6+ 中用 IActionResult 返回 SSE 流最简单
不需要引入第三方库,.NET 6 起内置了对 Server-Sent Events 的基础支持。核心是返回一个持续写入的 FileStreamResult 或更推荐的 StreamingFileResult 变体——但实际最稳妥的是直接用 HttpResponse 写入原始流,并手动设置响应头。
关键点:必须禁用响应缓冲、设置正确的 MIME 类型和缓存策略,否则浏览器收不到实时事件。
Response.StatusCode = 200Response.ContentType = "text/event-stream"Response.Headers.Add("Cache-Control", "no-cache")Response.Headers.Add("Connection", "keep-alive")- 调用
Response.Body.FlushAsync()每次写完一行后(尤其在开发环境 IIS Express 下容易卡住)
用 HttpResponse 手动写入 SSE 格式数据
SSE 协议本身极轻量:每条消息由若干字段行(data:、id:、event:、retry:)组成,空行分隔。浏览器只认 data: 开头的行,且会自动拼接多行 data: 成一个完整字符串。
示例片段(在 Controller Action 中):
Response.StatusCode = 200;
Response.ContentType = "text/event-stream";
Response.Headers.Add("Cache-Control", "no-cache");
Response.Headers.Add("Connection", "keep-alive");
var writer = new StreamWriter(Response.Body, Encoding.UTF8) { AutoFlush = true };
while (!HttpContext.RequestAborted.IsCancellationRequested)
{
await writer.WriteLineAsync($"data: {{\"time\":\"{DateTime.Now:O}\"}}");
await writer.WriteLineAsync("");
await Task.Delay(1000, HttpContext.RequestAborted);
}
注意:AutoFlush = true 很重要;若不用 StreamWriter,直接用 Response.Body.WriteAsync,记得每次写完调 FlushAsync。
避免 JsonSerializer 或 System.Text.Json 自动换行导致格式错误
如果用 JsonSerializer.Serialize 输出对象再写入流,它默认不换行,但你仍需手动加 data: 前缀和末尾空行。更麻烦的是,若 JSON 含换行符(如字符串里有 \n),SSE 会把它当成消息分隔,导致解析失败。