一個(gè)SSE(流式)接口引發(fā)的問題
前言
最近我們公司也是在做認(rèn)知助手,大模型相關(guān)的功能,正在做提示詞,機(jī)器人對話相關(guān)功能。想要提高用戶體驗(yàn),使用SSE請求模式,在不等數(shù)據(jù)完全拿到的情況下邊拿邊返回。
之前做過一版,但不是流式返回,是等待全部結(jié)果再返回,不得不說確實(shí)等待過程挺長,然后就有了現(xiàn)在的優(yōu)化。想著功能都寫好了,只是改一下接口,應(yīng)該是個(gè)簡單的需求。
后端使用的post接口,經(jīng)過一番搜索,最后使用的fetch。經(jīng)過短短幾個(gè)小時(shí),配置寫好,準(zhǔn)備聯(lián)調(diào),以為需求就順利完工了。奈何就這流式聯(lián)調(diào),還耗了兩天。只因?yàn)楹蠖嗽趐ostman上測試時(shí)正常的,然后前端在本地連調(diào)就是無法獲取分段式數(shù)據(jù),拿到的總是一整塊數(shù)據(jù)。表現(xiàn)成這樣,我們就開始糾結(jié)前端配置是否有誤,網(wǎng)關(guān)轉(zhuǎn)發(fā)是否有誤。
就這樣前端也試了好幾種方式去發(fā)請求,奈何結(jié)果都一樣。想著先測其他部分,這個(gè)接口最后測試。意外的是部署在線上的環(huán)境竟然能正常接收流式接口?。。∧菃栴}可能就是本地與部署線上的區(qū)別了,今天主要記錄一下使用的配置。
EventSource
創(chuàng)建EventSource對象:首先,使用new EventSource()構(gòu)造函數(shù)創(chuàng)建一個(gè)EventSource對象。該對象將用于與服務(wù)器建立連接并接收服務(wù)器發(fā)送的事件流。
var eventSource = new EventSource('sse_url');
在上面的代碼中,將'sse_url'替換為實(shí)際的SSE請求URL。2. 監(jiān)聽事件:使用EventSource對象的onmessage事件監(jiān)聽器來接收服務(wù)器發(fā)送的事件數(shù)據(jù)。當(dāng)接收到數(shù)據(jù)時(shí),事件處理函數(shù)將被調(diào)用,并可以通過事件對象的data屬性訪問數(shù)據(jù)。
eventSource.onmessage = function(event) {
console.log('Received data:', event.data);
};
錯(cuò)誤處理:為了處理可能發(fā)生的錯(cuò)誤,可以使用EventSource對象的onerror事件監(jiān)聽器。當(dāng)發(fā)生錯(cuò)誤時(shí),可以在事件處理函數(shù)中進(jìn)行處理。
eventSource.onerror = function(error) {
console.error('SSE error:', error);
};
關(guān)閉連接:當(dāng)不再需要接收事件流時(shí),可以使用EventSource對象的close方法關(guān)閉連接。
eventSource.close();
完整的示例代碼如下所示:
var eventSource = new EventSource('sse_url');
eventSource.onmessage = function(event) {
console.log('Received data:', event.data);
};
eventSource.onerror = function(error) {
console.error('SSE error:', error);
};
但是EventSource只支持get請求,配置請求頭也不太友好。
fetch
async function getStream() {
try {
let response = await fetch('url');
if (!response.ok) {
throw new Error('Network response was not ok');
}
const reader = response.body.getReader();
const textDecoder = new TextDecoder();
let result = true;
let output = ''
while (result) {
const { done, value } = await reader.read();
if (done) {
console.log('Stream ended');
result = false;
break;
}
const chunkText = textDecoder.decode(value);
output += chunkText;
console.log('Received chunk:', chunkText);
}
} catch (e) {
console.log(e);
}
}
插件
@microsoft/fetch-event-source 使用方法我就 不放了,看了一下源碼也是基于fetch實(shí)現(xiàn)的,網(wǎng)上例子很多,可以看看。
問題
本地運(yùn)行的環(huán)境也是用的代理訪問的部署好的環(huán)境的接口。插件是 Node.js 的 HTTP 代理中間件http-proxy-middleware。所以為何同樣的配置,本地運(yùn)行不行,而部署到環(huán)境上就正常了?有大佬遇到過嗎