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

IIS集成池模式下Node.js+Angular的SSE无法正常工作

IIS集成应用池下SSE事件延迟的问题与修复建议

问题概述

在IIS集成应用池模式下,Server-Sent Events(SSE)事件出现延迟:前端需等待后端整个调用完成后,才会一次性收到从0%到100%的所有进度数据,但本地用ng serve运行时完全正常。已尝试禁用text/event-stream的动态压缩,但无效果。

技术栈:Node.js后端生成SSE事件,Angular前端接收。已验证请求头设置正确,排除了经典模式的压缩问题。

相关代码

Node.js后端代码

app.get(Config.rootAPIPath + '/progress', (req, res) => {
    // Set headers for Server-Sent Events
    res.setHeader('Content-Type', 'text/event-stream');
    res.setHeader('Cache-Control', 'no-cache');
    res.setHeader('Connection', 'keep-alive');

    // Listen to progress events from business layer
    const progressListener = (data) => {
        res.write(`data: ${JSON.stringify(data)}

`);
        if (data.processed == 100) {
            res.write(`event: complete\ndata: {"processed": 100}\n\n`);
            res.end();
        }
    };

    Stream.on('progress', progressListener);
});

Angular组件代码

listenToServer() {
    this.eventSubscription = this.sseService.getServerSentEvents(`${Config.serverSideEventURL}progress`)
        .subscribe({
            next: (event: any) => {
                this.zone.run(() => {
                    console.log('Event received:', event);
                    this.progress = JSON.parse(event.data);
                    let counter = this.progress.processed;
                    if (isNullOrUndefined(counter))
                        this.counter = 0;
                    else
                        this.counter = +counter;

                     this.appRef.tick();
                });
            },
            complete: () => {
                console.log('SSE connection completed');
                this.isImporting = false;
            },
            error: (error) => {
                console.error('SSE error:', error);
                this.isImporting = false;
            }
        });
}

Angular SSE服务代码

export class ServerSideEventService {
    constructor(private ngZone: NgZone) { }

    getServerSentEvents(url: string): Observable<any> {
        return new Observable(observer => {
            const eventSource = new EventSource(url);

            eventSource.onmessage = (event) => {
                this.ngZone.run(() => {
                    observer.next(event);
                });
            };

            eventSource.addEventListener('complete', (event) => {
                this.ngZone.run(() => {
                    observer.complete();
                });
            });

            eventSource.onerror = (error) => {
                this.ngZone.run(() => {
                    observer.error(error);
                });
            };

            return () => eventSource.close();
        });
    }
}

修复建议

1. 强制Node.js响应立即推送

IIS可能会缓冲响应直到达到一定大小才发送,Node.js的res.write()默认不会立即将数据推送到客户端。每次调用res.write()后添加res.flush()(Express框架支持),确保数据即时发送:

const progressListener = (data) => {
    res.write(`data: ${JSON.stringify(data)}

`);
    res.flush(); // 强制推送数据到客户端
    if (data.processed == 100) {
        res.write(`event: complete\ndata: {"processed": 100}\n\n`);
        res.flush();
        res.end();
    }
};

如果用原生Node.js HTTP模块,没有flush()方法,可在设置响应头后添加res.socket.setNoDelay(true)禁用Nagle算法,避免小数据包合并:

res.socket.setNoDelay(true);

2. 配置IIS禁用响应缓冲

即使是集成模式,IIS仍可能对长连接响应缓冲。在web.config中添加以下配置,针对SSE路径禁用缓冲:

<system.webServer>
  <httpProtocol>
    <customHeaders>
      <add name="X-Accel-Buffering" value="no" /> <!-- 告诉代理不要缓冲 -->
    </customHeaders>
  </httpProtocol>
  <serverRuntime appConcurrentRequestLimit="1000" />
</system.webServer>

3. 确认动态压缩排除配置

确保text/event-stream类型的动态压缩已完全禁用,在web.config中明确配置:

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

4. 检查反向代理/防火墙设置

如果服务器前部署了ARR、防火墙等代理设备,它们可能会缓冲长连接响应。需在这些设备中添加规则,禁用对text/event-stream类型的缓冲,或允许流式传输。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 10:02:30