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

FeignClient调用SSE接口阻塞问题及流式返回实现咨询

解决FeignClient调用SSE接口无法流式返回的问题

问题现象

调用SSE接口时,FeignClient会等待所有数据接收完成后才一次性返回结果;而WebClient(或Spring 6 HTTP Interface)能实时逐段返回SSE数据——比如自定义的Mock接口每1秒返回一条数据,WebClient能立刻输出,Feign却要等10秒才全量输出。不管是自定义Mock SSE接口,还是OpenAI的对话SSE API,都存在该问题。

核心原因

默认Feign(包括未正确配置的ReactorFeign)基于阻塞式HTTP客户端实现,即使方法返回Flux,底层仍会将整个响应体读取完成后再封装成Flux返回,没有真正处理SSE的分块响应。要实现流式返回,必须配置专门的SSE解码器,让Feign能逐块解析响应。

解决方案步骤

1. 调整依赖

确保引入ReactorFeign核心依赖及对应解码器,以处理SSE分块和JSON解析(以OpenAI场景为例):

<dependency>
    <groupId>io.github.openfeign</groupId>
    <artifactId>feign-reactor-core</artifactId>
    <version>12.3</version>
</dependency>
<dependency>
    <groupId>io.github.openfeign</groupId>
    <artifactId>feign-reactor-jackson</artifactId>
    <version>12.3</version>
</dependency>
<dependency>
    <groupId>io.github.openfeign</groupId>
    <artifactId>feign-reactive-wrappers</artifactId>
    <version>12.3</version>
</dependency>

2. 配置ReactorFeign客户端

构建客户端时指定SseDecoder,让Feign能逐块解析SSE响应:

@Bean
public OpenAIClient openAIClient() {
    return ReactorFeign.builder()
            // 用SseDecoder处理分块响应,结合JacksonDecoder解析JSON格式的SSE事件
            .decoder(new SseDecoder(new JacksonDecoder()))
            .target(OpenAIClient.class, "https://api.openai.com");
}

如果是自定义的字符串类型SSE接口,替换成StringDecoder即可:

@Bean
public MockSSEClient mockSSEClient() {
    return ReactorFeign.builder()
            .decoder(new SseDecoder(new StringDecoder()))
            .target(MockSSEClient.class, "http://localhost:8080");
}

3. 修正Feign接口定义

添加Accept: text/event-stream请求头,明确告知服务端返回SSE格式,同时指定正确的返回类型:

public interface OpenAIClient {
    @RequestLine("POST /v1/chat/completions")
    @Headers({
            "Authorization: Bearer {apiKey}",
            "Accept: text/event-stream",
            "Content-Type: application/json"
    })
    // OpenAI的SSE返回是ChatCompletionChunk格式,而非直接返回String
    Flux<ChatCompletionChunk> getSSEStream(@Param("apiKey") String apiKey, ChatRequest request);
}

自定义Mock接口的示例:

public interface MockSSEClient {
    @RequestLine("GET /mockChatSteam")
    @Headers("Accept: text/event-stream")
    Flux<String> stream();
}

4. 控制器层流式返回

将Feign返回的Flux直接返回给前端,无需额外封装:

@GetMapping(value = "/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<String> stream() {
    ChatRequest request = new ChatRequest();
    // 填充对话请求参数
    return openAIClient.getSSEStream("your-openai-api-key", request)
            .map(chunk -> chunk.getChoices().get(0).getMessage().getContent())
            .filter(Objects::nonNull);
}

关键说明

  • SseDecoder是实现流式返回的核心,它会逐行读取响应体,每识别到一个SSE事件就立刻发送到Flux中,而非等待全量数据。
  • 必须显式设置Accept: text/event-stream请求头,避免服务端返回非流式的响应格式。
  • OpenAI的SSE返回是JSON分块,需用JacksonDecoder配合SseDecoder解析成对应实体类,不能直接用Flux<String>,否则会拿到未解析的原始JSON字符串。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 19:18:08