You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

IIS下Server Sent Events无法实时推送问题求助

IIS下ASP.NET MVC 4.7.2 Server-Sent Events推送丢失问题解决

我有一个基于ASP.NET Framework 4.7.2的MVC Web应用,用Server Sent Events(JavaScript的EventSource)实现服务器向客户端推送数据,明确不使用SignalR。在IIS Express上功能完全正常,但部署到IIS 10.0.22621.1554(Win11)后,仅约半数推送能到达浏览器,无固定规律,怀疑是IIS的缓存或缓冲机制导致。

当前代码

服务端C#控制器代码

[HttpGet]
public void Connect() {
    Response.ContentType = "text/event-stream";
    Response.CacheControl = "no-cache";
    Response.AddHeader("connection", "keep-alive"); 
    Response.Expires = -1;
    Response.Buffer = false;
    Response.BufferOutput = false;

    Response.Write("data: initialized\n\n");
    Response.Flush();

    var clientDisconnectedToken = Response.ClientDisconnectedToken;
    var client = ServerEventsHandler.Connect(currentUser);
    var cancelled = false;

    while (!cancelled && !clientDisconnectedToken.IsCancellationRequested) {
        var data = client.WaitForData(clientDisconnectedToken, out cancelled);

        if (!cancelled && !clientDisconnectedToken.IsCancellationRequested && data != null && data.Length > 0) {
            foreach (var item in data) {
                Response.Write($"data: {item.Data}\n\n");
                Response.Flush();
            }
        }
    }
        
    ServerEventsHandler.Disconnect(client);
    Response.Close();
}

客户端JavaScript代码

const url = "/ServerEvents/Connect";
const connection = new EventSource(url, { withCredentials: true });

connection.addEventListener("message", (e) => {
    // do stuff ...
}, false);

已尝试无效的操作

在web.config中禁用text/event-stream的动态压缩:

<httpCompression>
  <dynamicTypes>
    <add mimeType="text/event-stream" enabled="false" />
  </dynamicTypes>
</httpCompression>

解决方案

1. 强化服务端响应头,彻底禁用缓冲

在服务端Connect方法开头,添加更严格的缓存和缓冲禁用头部:

Response.AddHeader("X-Accel-Buffering", "no"); // 禁用反向代理/中间件缓冲
Response.AddHeader("Cache-Control", "no-cache, no-store, must-revalidate");
Response.AddHeader("Pragma", "no-cache");
Response.Expires = 0; // 覆盖原有的-1设置,确保过期时间为0

这些头部能强制IIS和任何中间件不缓冲SSE响应,保证数据实时推送。

2. 调整IIS应用程序池配置

打开IIS管理器,找到对应应用的应用程序池,进入高级设置:

  • 把队列长度设为1000以上,避免长连接被队列拒绝
  • 关闭快速失败保护(启用设为False),防止应用池因长时间连接被误回收
  • 设置**闲置超时(分钟)**为0,禁用闲置超时,保持长连接存活

3. 彻底禁用SSE内容的动态压缩

仅web.config的局部设置可能无效,需要确保服务器级和应用级都禁用:
在web.config的<system.webServer>节点下添加完整配置:

<system.webServer>
  <urlCompression doDynamicCompression="false" />
  <httpCompression>
    <dynamicTypes>
      <remove mimeType="text/event-stream" />
      <add mimeType="text/event-stream" enabled="false" />
    </dynamicTypes>
  </httpCompression>
</system.webServer>

如果需要保留其他动态内容压缩,可只保留<remove>和<add>节点,把doDynamicCompression设为True。

4. 添加心跳包防止连接空闲缓冲

IIS会对长时间无数据的连接进行缓冲,添加定期心跳包能保持连接活跃:
修改服务端循环逻辑,加入心跳超时处理:

while (!cancelled && !clientDisconnectedToken.IsCancellationRequested) {
    var timeoutTask = Task.Delay(30000); // 每30秒发一次心跳
    var dataTask = Task.Run(() => client.WaitForData(clientDisconnectedToken, out cancelled));
    var completedTask = Task.WhenAny(timeoutTask, dataTask);

    if (completedTask == timeoutTask) {
        // 发送SSE注释作为心跳,不会触发客户端message事件
        Response.Write(": heartbeat\n\n");
        Response.Flush();
    } else {
        var data = dataTask.Result;
        if (!cancelled && !clientDisconnectedToken.IsCancellationRequested && data != null && data.Length > 0) {
            foreach (var item in data) {
                Response.Write($"data: {item.Data}\n\n");
                Response.Flush();
            }
        }
    }
}

内容的提问来源于stack exchange,提问作者mrsubwoof

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 08:40:00