SpringAI系列---【WebClient调用sse接口(返回多行data: {...})的】

WebClient调用sse接口

我在fast-ai服务里写好了sse接口,能正常访问,返回sse流,由于fast-ai服务没有认证服务,所以我就用fast-server服务通过feign调用fast-ai的相关接口,但是发现fegin只能请求http的restful接口,sse接口无法请求。所以这里采用了webclient替代feign调用sse接口。
注意:controller接口给前端提供get请求,因为VUE的EventSource 标准只支持 GET,如果要 POST 参数,需要用 EventSource Polyfill,npm install event-source-polyfill,import { EventSourcePolyfill } from 'event-source-polyfill';

1.引入pom.xml

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-webflux</artifactId>
</dependency>

2.controller接口

    @Autowired
    private WebClient.Builder webClientBuilder;

    @GetMapping(value = "chat",produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public SseEmitter chat(String prompt) {
        SseEmitter sseEmitter = new SseEmitter(0L);
        WebClient webClient = webClientBuilder.baseUrl("http://localhost:8080").build();
        webClient.post()
                .uri("/api/chat")
                .header("Authorization", "Bearer xxxxx")
                .header("Content-Type", "application/json")
                .accept(MediaType.TEXT_EVENT_STREAM)
                .bodyValue(prompt)
                .retrieve()
                .bodyToFlux(String.class)
                .subscribe(
                        data -> {
                            try {
                                sseEmitter.send(SseEmitter.event().data(data));
                            } catch (IOException e) {
                                sseEmitter.completeWithError(e);
                            }
                        },
                        error -> sseEmitter.completeWithError(error),
                        sseEmitter::complete
                );
        return sseEmitter;
    }

3.把baseUrl优化成服务名调用

WebClient webClient = webClientBuilder.baseUrl("http://localhost:8080").build();

新增nacos作为注册中心

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>

新增webclient配置类

@Configuration
public class WebClientConfig {

    @Bean
    @LoadBalanced
    public WebClient.Builder webClientBuilder() {
        return WebClient.builder();
    }
}

此时,就可以把ip改成nacos注册中心的服务名

WebClient webClient = webClientBuilder.baseUrl("http://fast-ai").build();

4.前端代码

<template>
  <div>
    <textarea v-model="userText" placeholder="请输入问题"></textarea>
    <button @click="ask">提问</button>

    <div class="answer">
      <span v-for="(c, i) in answerChars" :key="i">{{ c }}</span>
    </div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      userText: "",
      sessionId: "123456",   // 你可以从登录态或接口里拿
      answer: "",
      answerChars: []
    }
  },
  methods: {
    ask() {
      this.answer = "";
      this.answerChars = [];

      // 用 EventSource 建立 SSE 连接
      const source = new EventSourcePolyfill("/server/askSse", {
        headers: {
          "Content-Type": "application/json"
        },
        // EventSource 标准只支持 GET,如果要 POST 参数,需要用 polyfill
        // polyfill: https://github.com/Yaffle/EventSource
        payload: JSON.stringify({
          sessionId: this.sessionId,
          userText: this.userText
        }),
        method: "POST"
      });

      source.onmessage = (event) => {
        const data = event.data;
        // 打字机效果:逐个字符 push 到数组
        for (let ch of data) {
          this.answerChars.push(ch);
        }
      };

      source.onerror = (err) => {
        console.error("SSE 连接错误:", err);
        source.close();
      };
    }
  }
}
</script>

posted on 2025-08-20 17:28  少年攻城狮  阅读(116)  评论(0)    收藏  举报

导航