Commit e17c6656 by Liu

feat:流式请求增加超时时间30分钟

parent d77ff208
...@@ -7,18 +7,29 @@ import { http } from '@/utils/request' ...@@ -7,18 +7,29 @@ import { http } from '@/utils/request'
export function fetchCheckTokenApi() { export function fetchCheckTokenApi() {
return http.post('/user/api/user_center/mobile/v1/check_token', {}) return http.post('/user/api/user_center/mobile/v1/check_token', {})
} }
const STREAM_TIMEOUT_MS = 30 * 60 * 1000 // 流式请求超时:半小时
export function fetchStreamResponse(url: string, body: Record<string, any>, onMessage: (msg: any) => void, signal?: AbortSignal): Promise<void> { export function fetchStreamResponse(url: string, body: Record<string, any>, onMessage: (msg: any) => void, signal?: AbortSignal): Promise<void> {
body.stream = true body.stream = true
const decoder = new TextDecoder('utf-8') const decoder = new TextDecoder('utf-8')
let buffer = '' let buffer = ''
let dataMsgBuffer = '' let dataMsgBuffer = ''
const controller = new AbortController()
const timeoutId = setTimeout(() => controller.abort(), STREAM_TIMEOUT_MS)
if (signal) {
signal.addEventListener('abort', () => controller.abort())
}
const effectiveSignal = controller.signal
const cleanup = () => clearTimeout(timeoutId)
return new Promise<void>((resolve, reject) => { return new Promise<void>((resolve, reject) => {
function processMessage(reader: any) { function processMessage(reader: any) {
reader.read().then((content: any) => { reader.read().then((content: any) => {
// 检查是否已被中止 // 检查是否已被中止
if (signal?.aborted) { if (effectiveSignal.aborted) {
resolve() // 中止时也 resolve,表示流已结束 cleanup()
resolve()
return return
} }
buffer += decoder.decode(content.value, { stream: !content.done }) buffer += decoder.decode(content.value, { stream: !content.done })
...@@ -61,20 +72,18 @@ export function fetchStreamResponse(url: string, body: Record<string, any>, onMe ...@@ -61,20 +72,18 @@ export function fetchStreamResponse(url: string, body: Record<string, any>, onMe
processMessage(reader) processMessage(reader)
} }
else { else {
// 流结束,resolve Promise(不再发送 END 消息) cleanup()
resolve() resolve()
} }
}).catch((error: unknown) => { }).catch((error: unknown) => {
// 如果是 AbortError,resolve 而不是 reject(因为这是主动取消)
if (error instanceof Error && error.name === 'AbortError') { if (error instanceof Error && error.name === 'AbortError') {
cleanup()
resolve() resolve()
return return
} }
onMessage({ onMessage({ type: 'ERROR', content: error })
type: 'ERROR', cleanup()
content: error, reject(error)
})
reject(error) // 其他错误 reject Promise
}) })
} }
const tokenStr = window.localStorage.getItem('__TOKEN__') || '""' const tokenStr = window.localStorage.getItem('__TOKEN__') || '""'
...@@ -94,30 +103,29 @@ export function fetchStreamResponse(url: string, body: Record<string, any>, onMe ...@@ -94,30 +103,29 @@ export function fetchStreamResponse(url: string, body: Record<string, any>, onMe
}, },
method: 'POST', method: 'POST',
body: JSON.stringify(body), body: JSON.stringify(body),
signal, signal: effectiveSignal,
}) })
.then((response) => { .then((response) => {
return response.body?.getReader() return response.body?.getReader()
}) })
.then((reader) => { .then((reader) => {
if (!reader) { if (!reader) {
cleanup()
reject(new Error('Failed to get reader from response')) reject(new Error('Failed to get reader from response'))
return return
} }
return processMessage(reader) return processMessage(reader)
}) })
.catch((error: unknown) => { .catch((error: unknown) => {
// 如果是 AbortError,resolve 而不是 reject(因为这是主动取消)
if (error instanceof Error && error.name === 'AbortError') { if (error instanceof Error && error.name === 'AbortError') {
cleanup()
resolve() resolve()
return return
} }
onMessage({ onMessage({ type: 'ERROR', content: error })
type: 'ERROR', cleanup()
content: error, reject(error)
}) })
reject(error)
})
}) })
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment