feat: 重新实现SseClient
This commit is contained in:
@@ -59,65 +59,69 @@ export class SseClient {
|
|||||||
this._connecting = true
|
this._connecting = true
|
||||||
this.abortController = new AbortController()
|
this.abortController = new AbortController()
|
||||||
|
|
||||||
await fetchEventSource(this.url, {
|
try {
|
||||||
headers: { saToken: token },
|
await fetchEventSource(this.url, {
|
||||||
signal: this.abortController.signal,
|
headers: { saToken: token },
|
||||||
openWhenHidden: true,
|
signal: this.abortController.signal,
|
||||||
|
openWhenHidden: true,
|
||||||
|
|
||||||
onopen: async (response) => {
|
onopen: async (response) => {
|
||||||
const contentType = response.headers.get('content-type') || ''
|
const contentType = response.headers.get('content-type') || ''
|
||||||
|
|
||||||
if (response.status === 401) {
|
if (response.status === 401) {
|
||||||
throw new SseHttpError('SSE 鉴权失败', response)
|
throw new SseHttpError('SSE 鉴权失败', response)
|
||||||
|
}
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new SseHttpError(`SSE 连接失败: ${response.status}`, response)
|
||||||
|
}
|
||||||
|
if (!contentType.includes('text/event-stream')) {
|
||||||
|
throw new SseHttpError(`非法的响应类型: ${contentType || '空'}`, response)
|
||||||
|
}
|
||||||
|
|
||||||
|
this._connecting = false
|
||||||
|
this._connected = true
|
||||||
|
this.retryCount = 0
|
||||||
|
this.callbacks.onConnected?.()
|
||||||
|
},
|
||||||
|
|
||||||
|
onmessage: (message) => {
|
||||||
|
if (!message.event || !message.data) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.callbacks.onMessage(message.event, message.data)
|
||||||
|
},
|
||||||
|
|
||||||
|
onclose: () => {
|
||||||
|
this._connecting = false
|
||||||
|
this._connected = false
|
||||||
|
},
|
||||||
|
|
||||||
|
onerror: (error) => {
|
||||||
|
this._connecting = false
|
||||||
|
this._connected = false
|
||||||
|
|
||||||
|
// 401 → 通知外部刷新 token
|
||||||
|
if (isSseHttpError(error) && error.response.status === 401) {
|
||||||
|
this.callbacks.onUnauthorized?.()
|
||||||
|
throw error
|
||||||
|
}
|
||||||
|
|
||||||
|
this.retryCount += 1
|
||||||
|
if (this.retryCount >= this.maxRetries) {
|
||||||
|
this.callbacks.onError?.('实时连接异常,请刷新页面')
|
||||||
|
throw error
|
||||||
|
}
|
||||||
|
|
||||||
|
const delay = Math.min(
|
||||||
|
this.baseRetryDelayMs * Math.pow(2, this.retryCount - 1),
|
||||||
|
this.maxRetryDelayMs
|
||||||
|
)
|
||||||
|
return delay
|
||||||
}
|
}
|
||||||
if (!response.ok) {
|
})
|
||||||
throw new SseHttpError(`SSE 连接失败: ${response.status}`, response)
|
} catch (error) {
|
||||||
}
|
// fetchEventSource 仅在重连耗尽或 401 时 throw,状态已在 onerror 中处理
|
||||||
if (!contentType.includes('text/event-stream')) {
|
}
|
||||||
throw new SseHttpError(`非法的响应类型: ${contentType || '空'}`, response)
|
|
||||||
}
|
|
||||||
|
|
||||||
this._connecting = false
|
|
||||||
this._connected = true
|
|
||||||
this.retryCount = 0
|
|
||||||
this.callbacks.onConnected?.()
|
|
||||||
},
|
|
||||||
|
|
||||||
onmessage: (message) => {
|
|
||||||
if (!message.event || !message.data) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
this.callbacks.onMessage(message.event, message.data)
|
|
||||||
},
|
|
||||||
|
|
||||||
onclose: () => {
|
|
||||||
this._connecting = false
|
|
||||||
this._connected = false
|
|
||||||
},
|
|
||||||
|
|
||||||
onerror: (error) => {
|
|
||||||
this._connecting = false
|
|
||||||
this._connected = false
|
|
||||||
|
|
||||||
// 401 → 通知外部刷新 token
|
|
||||||
if (isSseHttpError(error) && error.response.status === 401) {
|
|
||||||
this.callbacks.onUnauthorized?.()
|
|
||||||
throw error
|
|
||||||
}
|
|
||||||
|
|
||||||
this.retryCount += 1
|
|
||||||
if (this.retryCount >= this.maxRetries) {
|
|
||||||
this.callbacks.onError?.('实时连接异常,请刷新页面')
|
|
||||||
throw error
|
|
||||||
}
|
|
||||||
|
|
||||||
const delay = Math.min(
|
|
||||||
this.baseRetryDelayMs * Math.pow(2, this.retryCount - 1),
|
|
||||||
this.maxRetryDelayMs
|
|
||||||
)
|
|
||||||
return delay
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 断开连接(主动关闭,不重连) */
|
/** 断开连接(主动关闭,不重连) */
|
||||||
|
|||||||
Reference in New Issue
Block a user