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>
愿你走出半生,归来仍是少年!
浙公网安备 33010602011771号