获取第三方接口的EventStream返回给前端
最近项目有个需求,获取第三方gpt接口提供的AI聊天服务,回显给前端,其实就是http请求第三方接口并拿到EventStream流,推送给前端。
试了下RestTemplate,不太理想,于是使用WebFlux,直接上核心代码:
后端:
privatestatic SseEmitter sendEventStreamPost(String url, String jsonData){
SseEmitter emitter =newSseEmitter();
Mono.fromCallable(()->{
WebClient.create(url).post().contentType(MediaType.APPLICATION_JSON).accept(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);}).doOnComplete(()->{
emitter.complete();}).subscribe();return emitter;}).subscribeOn(Schedulers.boundedElastic()).subscribe();return emitter;}
其中曾踩了一些坑:
1.原本是bodyToFlux(String.class),结果没有返回也没有报错,排查了许久,最终改成bodyToFlux(byte[].class)
2.原本未使用Mono.fromCallable进行异步请求,结果其实是一次获取到完整的流再给前端,与长连接实时输出信息相悖。实际应该把SseEmitter返回给前端,异步调用接口对SseEmitter进行写入并且在完成后emitter.complete()关闭流。
前端,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 =thisfetchEventSource(url,{method:'POST',headers:{"Content-Type":'application/json',"Accept":"*/*"},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时并未断开连接,等解决了再编辑
版权归原作者 咩丫 所有, 如有侵权,请联系我们删除。