You need to enable JavaScript to run this app. F#中基于System.Net.Http实现SSE事件流推送至前端的轻量方案咨询
优惠活动
大模型
产品
解决方案
定价
更多

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.Core NuGet包
  • 无需引入其他第三方组件,全部基于原生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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.07 18:36:02