F#中基于System.Net.Http实现SSE事件流推送至前端的轻量方案咨询
.NET Framework 4.8 环境下F#实现SSE事件流推送的轻量方案
注意:System.Net.Http 属于客户端类库,服务端流式输出用到的PushStreamContent是该库提供的兼容类型,搭配ASP.NET Web API 2(.NET Framework 4.8 官方推荐的HTTP服务框架)即可实现无第三方依赖的SSE推送。
1 前置依赖
- 项目需安装适配.NET Framework 4.8的
Microsoft.AspNet.WebApi.CoreNuGet包 - 无需引入其他第三方组件,全部基于原生API实现
2 核心实现代码
2.1 SSE消息格式生成辅助函数
open System // 生成符合规范的SSE格式消息 let buildSseMessage (eventName: string option) (data: string) (eventId: string option) = [ if eventId.IsSome then $"id: {eventId.Value}\n" if eventName.IsSome then $"event: {eventName.Value}\n" for line in data.Split([|'\n'|], StringSplitOptions.RemoveEmptyEntries) do $"data: {line}\n" "\n" // 单条消息必须以空行结尾,是SSE协议的强制要求 ] |> String.concat ""
2.2 流式推送接口实现
open System open System.Net.Http open System.Net.Http.Headers open System.Web.Http open System.IO open System.Text open System.Threading.Tasks type SseController() = inherit ApiController() [<HttpGet>] [<Route("api/sse/stream")>] member this.GetEventStream() = let response = this.Request.CreateResponse() // 核心:使用PushStreamContent实现逐段流式输出 response.Content <- new PushStreamContent( action = fun stream httpContent transportContext -> // 推送逻辑放入独立异步任务执行,避免阻塞ASP.NET请求线程 Task.Run(fun () -> use writer = new StreamWriter(stream, Encoding.UTF8) try // 示例逻辑:每隔2秒推送1条消息,共推送10次后断开 for seqNum in 1..10 do let message = buildSseMessage (Some "message") $"推送序号:{seqNum},服务端时间:{DateTime.Now:HH:mm:ss}" (Some (string seqNum)) writer.Write(message) writer.Flush() Task.Delay(2000).Wait() // 推送结束后可主动发送关闭事件通知前端 let closeMsg = buildSseMessage (Some "close") "所有消息推送完成" None writer.Write(closeMsg) writer.Flush() with | :? IOException -> // 前端主动断开连接时会触发IO异常,直接释放资源即可 () ) :> Task , mediaType = MediaTypeHeaderValue.Parse("text/event-stream") ) // 必须禁用缓存,否则浏览器会缓存响应导致无法实时接收消息 response.Headers.CacheControl <- CacheControlHeaderValue(NoCache = true) response
3 关键注意事项
- 响应头要求:
Content-Type必须固定为text/event-stream,否则浏览器无法识别为SSE流 - 消息格式要求:所有消息必须以空行结尾,多行内容的每一行都需要加
data:前缀 - 资源释放:流写入完成或者出现异常时必须主动释放
StreamWriter和输出流资源,避免服务端资源泄漏 - 并发优化:推送逻辑不要同步阻塞请求线程,用异步任务执行可以大幅提升服务端并发承载能力
4 前端调用参考(可选)
// 建立SSE连接 const sse = new EventSource('/api/sse/stream'); // 监听默认message事件 sse.addEventListener('message', e => { console.log('收到服务端消息:', e.data, '消息ID:', e.lastEventId); }); // 监听自定义关闭事件 sse.addEventListener('close', () => { sse.close(); console.log('服务端推送结束,连接已关闭'); }); // 错误处理 sse.onerror = err => { console.error('SSE连接异常:', err); sse.close(); };
内容的提问来源于stack exchange,提问作者Janthelme
相关产品推荐
相关产品推荐

