发送SSE GET请求遇413错误的解决方法及长文本传输方案
解决SSE GET请求413 Request Entity Too Large及长文本发送问题
遇到413 request entity too large是因为GET请求的URL(含查询参数)长度超过了服务器或浏览器的限制,而原生EventSource确实仅支持GET方法。以下是几种可行的解决思路:
方案一:预上传长文本,用ID引用
先通过POST请求将长文本(比如你的prompt)上传到服务器,服务器返回一个唯一标识ID,之后用这个ID作为查询参数发起SSE请求,避免URL过长。
修改后的代码示例:
import { ChatAsk } from '@/models/request/chat/ChatAsk'; import { EventSourcePolyfill } from 'event-source-polyfill'; import { v4 as uuid } from 'uuid'; // 新增上传长文本的函数 async function uploadLongPrompt(prompt: string): Promise<string> { const accessToken = localStorage.getItem("x-access-token"); const response = await fetch('/ai/upload-prompt', { method: 'POST', headers: { 'Content-Type': 'application/json', 'x-access-token': accessToken ?? "", 'x-request-id': uuid(), }, body: JSON.stringify({ prompt }) }); const data = await response.json(); return data.promptId; // 假设服务器返回包含promptId的JSON } export async function doSseChatAsk(params: ChatAsk, onSseMessage: (msg: string) => void,) { let eventSource: EventSourcePolyfill; const accessToken = localStorage.getItem("x-access-token"); // 上传长prompt,获取ID const promptId = await uploadLongPrompt(params.prompt); // 替换原params中的prompt为promptId const modifiedParams = { ...params, prompt: promptId }; const queryString = Object.keys(modifiedParams).map(key => key + '=' + modifiedParams[key as keyof ChatAsk]).join('&'); eventSource = new EventSourcePolyfill('/ai/stream/chat/ask?' + queryString, { headers: { 'x-access-token': accessToken ?? "", 'x-request-id': uuid(), } }); // 以下原有的事件监听逻辑保留 eventSource.onopen = () => { console.log("onopen....") } eventSource.onerror = (error) => { console.log("onerror", error) if(eventSource){ eventSource.close(); } } eventSource.onmessage = e => { onSseMessage(e.data); }; eventSource.addEventListener('complete', () => { console.log('Transfer of data is complete'); }); eventSource.addEventListener('onclose', () => { console.log('Transfer of data is complete'); }); }
服务器端需要新增一个接收POST请求的接口(比如/ai/upload-prompt),存储prompt并返回ID;同时修改原SSE接口,通过ID获取对应的prompt内容。
方案二:用Fetch API + ReadableStream实现自定义SSE客户端
放弃EventSource,直接使用fetch发起POST请求(可以携带长文本在请求体中),同时处理服务器返回的流式响应,模拟SSE的行为。
代码示例:
import { ChatAsk } from '@/models/request/chat/ChatAsk'; import { v4 as uuid } from 'uuid'; export async function doSseChatAsk(params: ChatAsk, onSseMessage: (msg: string) => void,) { const accessToken = localStorage.getItem("x-access-token"); const requestId = uuid(); try { const response = await fetch('/ai/stream/chat/ask', { method: 'POST', headers: { 'Content-Type': 'application/json', 'x-access-token': accessToken ?? "", 'x-request-id': requestId, }, body: JSON.stringify(params) // 直接把长文本放在请求体中 }); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } const reader = response.body?.getReader(); if (!reader) return; const decoder = new TextDecoder(); let buffer = ''; // 处理流式响应 while (true) { const { done, value } = await reader.read(); if (done) break; buffer += decoder.decode(value, { stream: true }); // 按SSE的消息分隔符分割(通常是\n\n) const messages = buffer.split('\n\n'); buffer = messages.pop() || ''; for (const msg of messages) { if (msg.startsWith('data:')) { const data = msg.slice(5).trim(); onSseMessage(data); } else if (msg === 'event: complete') { console.log('Transfer of data is complete'); } } } } catch (error) { console.log("onerror", error); } }
这个方案需要服务器端支持POST请求的流式响应,并且返回符合SSE格式的内容(每条消息以data:开头,用\n\n分隔)。
方案三:调整服务器端URL长度限制(临时方案)
如果你有权限修改服务器配置,可以调高GET请求的URL长度限制(比如Nginx的client_max_body_size、Apache的LimitRequestLine等)。但这种方式有局限性:浏览器对URL长度有原生限制(不同浏览器上限不同,一般在2MB以内),超长文本依然会触发问题,所以不推荐作为长期解决方案。
内容的提问来源于stack exchange,提问作者Dolphin
相关产品推荐
相关产品推荐

