后端:
javascript"> private static SseEmitter sendEventStreamPost(String url, String jsonData){
SseEmitter emitter = new SseEmitter();
Mono.fromCallable(() -> {
WebClient.create(url)
.post()
.contentType(MediaType.APPLICATION_JSON)
.a***ept(MediaType.TEXT_EVENT_STREAM)
.body(BodyInserters.fromValue(jsonData))
.retrieve()
.bodyToFlux(byte[].class)
.doOnNext(data -> {
try {
emitter.send(data);
} catch (IOException e) {
log.error("Event Stream Exception:" + e);
}
})
.doOnError(error -> {
log.error("Event Stream Error:" + error);
})
.doOn***plete(() -> {
emitter.***plete();
})
.subscribe();
return emitter;
})
.subscribeOn(Schedulers.boundedElastic())
.subscribe();
return emitter;
}
其中曾踩了一些坑:
1.原本是bodyToFlux(String.class),结果没有返回也没有报错,排查了许久,最终改成bodyToFlux(byte[].class)
2.原本未使用Mono.fromCallable进行异步请求,结果其实是一次获取到完整的流再给前端,与长连接实时输出信息相悖。实际应该把SseEmitter返回给前端,异步调用接口对SseEmitter进行写入并且在完成后emitter.***plete()关闭流。
前端,vue框架:
import { fetchEventSource } from '@microsoft/fetch-event-source'
methods: {
test() {
var data = {
sendContent: "你好,你能帮我做些什么"
}
if ('EventSource' in window) {
const url = 'http://xxx/api/help/chat/sendMsgStream'
var _this = this
fetchEventSource(url, {
method: 'POST',
headers: {
"Content-Type": 'application/json',
"A***ept": "*/*"
},
body: JSON.stringify(data),
onmessage(event) {
console.info("event.data:", event.data);
const eventData = event.data
_this.msg += eventData
},
onerror(err) {
console.log('err:',err)
}
})
} else {
console.log("error")
}
}
}
其中msg绑定的是聊天窗口的机器人答复,目前前端代码并不完善,在eroor时并未断开连接,等解决了再编辑