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

Spring WebFlux SSE重试时如何更新Last-Event-ID请求头

解决SSE重试时更新Last-Event-ID请求头的问题

问题根源在于原代码中请求对象req是一次性初始化的,重试时复用的是同一个已设置好初始Last-Event-ID的实例,无法动态更新头信息。要解决这个问题,需要让每次重试时都重新构建请求,加载最新的Last-Event-ID。

具体实现方案

使用Mono.defer()包装请求构建逻辑,defer会在每次订阅(包括重试触发的重新订阅)时执行内部代码,这样每次都能获取最新的事件ID并设置到请求头中。

修改后的完整代码

var type = new ParameterizedTypeReference<ServerSentEvent<String>>() {};

Mono.defer(() -> {
        // 每次订阅(含重试)都会重新加载最新的Last-Event-ID
        String lastEventId = loadLastId();
        var req = webClient.get()
                .uri("/the/end/point");
        
        if (lastEventId != null && !lastEventId.isEmpty()) {
            req = req.header("Last-Event-ID", lastEventId);
        }
        
        return req.retrieve().bodyToFlux(type);
    })
    .retryWhen(Retry
        .backoff(maxRetries, Duration.ofSeconds(retryBackoffStep))
        .maxBackoff(Duration.ofSeconds(10))
        .transientErrors(true)
        .filter(t -> {
            log.warn("SSE Notification Channel: connection error detected", t);
            return !(t instanceof ClientAuthorizationException)
                && !(t instanceof WebClientResponseException.Forbidden)
                && !(t instanceof WebClientResponseException.NotFound);
        })
        .doBeforeRetry(signal -> {
            log.warn("SSE Notification Channel: retry SSE connection, attempt {}",
                            signal.totalRetriesInARow() + 1);
        })
        .doAfterRetry(signal ->
            log.warn("SSE Notification Channel: retried SSE connection, attempt {}, successful = {}",
                            signal.totalRetriesInARow() + 1, signal.failure() == null))
        .onRetryExhaustedThrow((retryBackoffSpec, signal) -> {
            log.error("SSE Notification Channel: SSE connection retries exhausted");
            return signal.failure();
        })
    )
    .subscribe(
        this::handleContent,
        this::handleError,
        () -> log.error("SSE Notification Channel: SSE connection closed")
    );

关键改动说明

  • 将请求构建逻辑移入Mono.defer()内部,确保每次重试触发重新订阅时,都会执行loadLastId()获取最新的事件ID,再动态设置请求头。
  • 替换原有的一次性请求对象为动态生成的请求实例,从根本上解决重试时头信息无法更新的问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 20:34:56