将http轮询改为 长轮询请求挂起

This commit is contained in:
nnwang
2025-12-06 01:02:28 +08:00
parent e5708e10fb
commit 83822ae165
5 changed files with 506 additions and 390 deletions

View File

@@ -2,7 +2,7 @@ import type { Files } from 'monaco-tree-editor'
let roomId: string | null = null
let serverUrl: string | null = null
let pollIntervalMs = 1000
let pollIntervalMs = 100
let isPolling = false
let pollingTimeout: number | null = null
@@ -32,29 +32,6 @@ function getParamsFromUrl(): { roomId: string | null } {
return { roomId }
}
async function httpPost(path: string, data: any): Promise<any> {
const url = `${serverUrl}${path}`
try {
const response = await fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(data),
})
if (!response.ok) {
throw new Error(`HTTP错误: ${response.status} ${response.statusText}`)
}
return await response.json()
} catch (error) {
console.error('HTTP请求失败:', error)
throw error
}
}
export async function initWebSocketConnection(): Promise<void> {
const params = getParamsFromUrl()
roomId = params.roomId
@@ -67,6 +44,17 @@ export async function initWebSocketConnection(): Promise<void> {
console.log('HTTP连接已初始化服务器:', serverUrl)
console.log('房间ID:', roomId)
// 处理挂起的初始请求
for (const request of pendingInitialRequests) {
try {
const result = await sendFileOperationInternal(request.operation, request.data)
request.resolve(result)
} catch (error) {
request.reject(error as Error)
}
}
pendingInitialRequests.length = 0
startPolling()
return Promise.resolve()
}
@@ -86,18 +74,33 @@ function stopPolling() {
}
async function pollForResponses() {
if (!isPolling || !roomId) return
if (!isPolling || !roomId || !serverUrl) return
try {
const response = await httpPost('/api/frontend/receive', {
room_id: roomId,
const response = await fetch(`${serverUrl}/api/frontend/receive`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
room_id: roomId,
}),
})
if (response.success && response.message) {
handleMessage(response.message)
if (response.ok) {
const data = await response.json()
if (data.success && data.message) {
handleMessage(data.message)
}
} else {
console.error('轮询请求失败:', response.status)
// 短暂的延迟后重试
await new Promise((resolve) => setTimeout(resolve, 2000))
}
} catch (error) {
console.error('轮询消息失败:', error)
// 网络错误,稍后重试
await new Promise((resolve) => setTimeout(resolve, 5000))
}
if (isPolling) {
@@ -130,8 +133,13 @@ function handleFileOperationResponse(data: any): void {
}
}
function sendFileOperationInternal(operationType: string, data?: any, timeoutMs: number = 30000): Promise<any> {
async function sendFileOperationInternal(operationType: string, data?: any, timeoutMs: number = 30000): Promise<any> {
return new Promise((resolve, reject) => {
if (!serverUrl || !roomId) {
reject(new Error('未初始化连接'))
return
}
const requestId = generateRequestId()
const timeout = window.setTimeout(() => {
@@ -143,21 +151,28 @@ function sendFileOperationInternal(operationType: string, data?: any, timeoutMs:
pendingRequests.set(requestId, { resolve, reject, timeout })
httpPost('/api/frontend/send', {
room_id: roomId,
message: {
type: 'file_operation',
requestId: requestId,
operation_type: operationType,
data: data,
room_id: roomId,
fetch(`${serverUrl}/api/frontend/send`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
room_id: roomId,
message: {
type: 'file_operation',
requestId: requestId,
operation_type: operationType,
data: data,
room_id: roomId,
},
}),
})
.then((response) => {
if (!response.success) {
.then(async (response) => {
if (!response.ok) {
const errorText = await response.text()
pendingRequests.delete(requestId)
clearTimeout(timeout)
reject(new Error(response.message || '发送请求失败'))
reject(new Error(errorText || `发送请求失败: ${response.status}`))
}
})
.catch((error) => {