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

NodeJS的microsoft/fetch-event-source API本地正常但Azure上onmessage失效

Azure环境下Server-Sent Events(SSE) onmessage逻辑异常排查与解决建议

问题场景

本地Node.js 18.15.0环境中,基于fetchEventSource实现的SSE客户端可正常处理[DONE]结束标识和FatalError自定义事件,但部署至Azure(Node.js 18.12.0)后,进入if (event.data === '[DONE]')分支后无法正常执行后续操作,同时监听FatalError事件的代码也完全失效。

客户端核心代码

await fetchEventSource('/api/chat', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({
          question,
          history,
        }),
        signal: ctrl.signal,
        onmessage(event) {
          if (event.data === '[DONE]') {
            setMessageState((state) => ({
              history: [...state.history, [question, state.pending ?? '']],
              messages: [
                ...state.messages,
                {
                  type: 'apiMessage',
                  message: state.pending ?? '',
                  sourceDocs: state.pendingSourceDocs,
                },
              ],
              pending: undefined,
              pendingSourceDocs: undefined,
            }));
            setLoading(false);
            ctrl.abort();
          } else {
            const data = JSON.parse(event.data);
            if (data.sourceDocs) {
              setMessageState((state) => ({
                ...state,
                pendingSourceDocs: data.sourceDocs,
              }));
            } else {
              setMessageState((state) => ({
                ...state,
                pending: (state.pending ?? '') + data.data,
              }));
            }
          }
        },
      });

失效的自定义事件监听代码

onmessage(msg) {
        // if the server emits an error message, throw an exception
        // so it gets handled by the onerror callback below:
        if (msg.event === 'FatalError') {
            throw new FatalError(msg.data);
        }
    },

排查与解决建议

1. 对齐Node.js版本差异

Node.js 18.12.0到18.15.0之间,fetch/EventSource相关API存在多处修复:

  • 验证消息内容一致性:18.12.0可能对SSE消息的换行符、空白字符处理逻辑不同,导致[DONE]被额外字符包裹。可在onmessage开头添加日志确认:
    console.log('Received event data:', JSON.stringify(event.data));
    
    若存在空白字符,可改为模糊匹配:
    if (event.data.trim() === '[DONE]')
    
  • 升级Azure Node.js版本:直接将Azure环境的Node.js版本升级至18.15.0+,规避底层API的兼容问题。

2. 检查Azure网络层的SSE兼容性

Azure App Service、Front Door等组件可能对长连接做了特殊处理:

  • 确保服务器端响应头正确配置:Cache-Control: no-cache、Connection: keep-alive、Content-Type: text/event-stream
  • 若使用CDN或Front Door,需禁用缓存并开启SSE支持,避免消息被截断或合并。

3. 调整ctrl.abort()执行时机

Azure环境中,ctrl.abort()可能在React状态更新完成前终止连接,导致状态变更被中断:

  • 若使用支持回调的状态管理工具,可将abort放在状态更新回调中执行;若使用React原生useState,可通过useEffect监听状态变化,当pending变为undefined时再执行abort:
    useEffect(() => {
      if (!messageState.pending) {
        setLoading(false);
        ctrl.abort();
      }
    }, [messageState.pending]);
    

4. 修正自定义事件监听逻辑

标准SSE中自定义事件需通过addEventListener单独监听,原代码可能依赖第三方库的特殊实现,在Node.js 18.12.0中存在兼容问题:

await fetchEventSource('/api/chat', {
  // ...其他配置项
  onmessage(event) {
    // 处理默认message事件逻辑
  },
  onopen(response) {
    // 单独监听FatalError自定义事件
    response.addEventListener('FatalError', (msg) => {
      throw new FatalError(msg.data);
    });
  }
});

内容的提问来源于stack exchange,提问作者Malatesha Somasundar Anantha

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 04:13:28