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

如何在Spring DeferredResult场景下感知服务端关闭ReadableStream连接

处理服务端连接关闭的轮询优化方案

1. 给Fetch请求添加超时机制

原生Fetch没有内置超时功能,可通过AbortController手动实现,避免客户端无限等待。修改后的客户端代码如下:

function polling() {
    console.log("call with fetch");
    // 创建AbortController实例用于中断请求
    const controller = new AbortController();
    const signal = controller.signal;
    // 设置超时时间(示例为5分钟,可根据业务调整)
    const timeoutId = setTimeout(() => controller.abort(), 5 * 60 * 1000);

    fetch('%@[urlPolling]', { signal })
     .then(function(response) {
           clearTimeout(timeoutId); // 请求正常返回,清除超时定时器
           console.log(response);
           // 检查响应状态,服务端连接异常可能返回5xx/4xx状态码
           if (!response.ok) {
               throw new Error(`HTTP error! status: ${response.status}`);
           }
           return response.text();
         }).then(function(data) {
           console.log(data);
           var dataJson = JSON.parse(data);
           if (dataJson.status == "OK" || dataJson.status == "KO") {
                addLoaderEffect();
                console.log("completato");
                sendPollingResult();
            } else if (dataJson.status == "ERROR") {
                console.log("error from server, executing polling again");
                setTimeout(polling, 3000);
            } else {
                // 未知状态触发重试
                setTimeout(polling, 3000);
            }
         })
     .catch((error) => {
       console.error('Error:', error);
       // 根据错误类型区分场景
       if (error.name === 'AbortError') {
           console.log("Request timed out, retrying...");
       } else {
           console.log("Connection closed or server error, retrying...");
       }
       setTimeout(polling, 3000);
     });
}

polling();

2. 精准识别连接关闭场景

在catch块中,不同错误类型对应不同的服务端状态:

  • AbortError:主动触发的超时,说明服务端长时间无响应,大概率已下线
  • TypeError(如"Failed to fetch"):网络连接中断,包含服务端主动关闭连接、实例被替换的情况
  • HTTP状态码错误(502/503等):服务端实例替换时可能返回这类状态,需在then阶段通过response.ok提前判断

3. 服务端配合优化

在Spring的DeferredResult逻辑中添加超时和完成回调,主动向客户端返回状态标识:

// Spring端示例代码
DeferredResult<String> deferredResult = new DeferredResult<>(5 * 60 * 1000L); // 设置服务端超时时间
// 超时回调:主动返回超时状态
deferredResult.onTimeout(() -> {
    deferredResult.setResult(JSON.toJSONString(Map.of("status", "TIMEOUT")));
});
// 连接完成/关闭时的清理回调
deferredResult.onCompletion(() -> {
    // 可在此处添加资源清理逻辑,若需主动告知客户端连接关闭,也可返回对应状态
});
// 业务逻辑中设置正常结果
// deferredResult.setResult(...);

客户端收到TIMEOUT状态后可直接重试,无需等待。

4. 可选:心跳辅助检测

如果轮询间隔较长,可在轮询间隙添加轻量心跳请求(比如每30秒调用一次服务端健康检查接口),一旦心跳失败,立即触发轮询重试,快速感知服务端状态变化。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 16:55:23