|
|
|
|
@ -10,6 +10,26 @@ class WebSocketClient { |
|
|
|
|
this.maxReconnectAttempts = 5 |
|
|
|
|
this.reconnectInterval = 3000 |
|
|
|
|
this.connected = false |
|
|
|
|
// token传递方式: 'url'(默认,URL参数), 'header'(请求头), 'message'(首次消息)
|
|
|
|
|
this.tokenMode = 'url' |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 设置token传递方式
|
|
|
|
|
setTokenMode(mode) { |
|
|
|
|
const validModes = ['url', 'header', 'message'] |
|
|
|
|
if (validModes.includes(mode)) { |
|
|
|
|
this.tokenMode = mode |
|
|
|
|
console.log(`WebSocket token传递方式已设置为: ${mode}`) |
|
|
|
|
|
|
|
|
|
// 特别说明header模式的限制
|
|
|
|
|
if (mode === 'header') { |
|
|
|
|
console.warn('注意: header模式使用WebSocket子协议传递token,受浏览器API限制,实际token将通过Sec-WebSocket-Protocol头传递') |
|
|
|
|
console.warn('后端需要从Sec-WebSocket-Protocol请求头中提取token信息') |
|
|
|
|
} |
|
|
|
|
return true |
|
|
|
|
} |
|
|
|
|
console.error('无效的token传递方式,可选值: url, header, message') |
|
|
|
|
return false |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 初始化WebSocket连接
|
|
|
|
|
@ -24,7 +44,6 @@ class WebSocketClient { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 获取token并检查登录状态
|
|
|
|
|
// 检查token有效性
|
|
|
|
|
const token = getToken() |
|
|
|
|
if (!token) { |
|
|
|
|
console.warn('WebSocket初始化失败: 未获取到token,请先登录') |
|
|
|
|
@ -47,8 +66,14 @@ class WebSocketClient { |
|
|
|
|
let wsProtocol = baseURL.includes('https') ? 'wss' : 'ws' |
|
|
|
|
let wsBaseURL = baseURL.replace(/^https?:\/\//, '') |
|
|
|
|
|
|
|
|
|
// 将token添加到URL查询参数
|
|
|
|
|
this.url = `${wsProtocol}://${wsBaseURL}/ws/onlineMessage?userId=${userId}&token=${token}` |
|
|
|
|
// 根据token传递方式构建URL
|
|
|
|
|
if (this.tokenMode === 'url') { |
|
|
|
|
// 在token前面加上'token-'前缀
|
|
|
|
|
this.url = `${wsProtocol}://${wsBaseURL}/ws/onlineMessage?token=token-${token}` |
|
|
|
|
} else { |
|
|
|
|
// header或message模式下,URL不包含token
|
|
|
|
|
this.url = `${wsProtocol}://${wsBaseURL}/ws/onlineMessage` |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 输出环境变量和配置信息以调试
|
|
|
|
|
console.log('WebSocket配置:', { |
|
|
|
|
@ -56,7 +81,8 @@ class WebSocketClient { |
|
|
|
|
userId, |
|
|
|
|
wsProtocol, |
|
|
|
|
wsBaseURL, |
|
|
|
|
hasToken: !!token |
|
|
|
|
hasToken: !!token, |
|
|
|
|
tokenMode: this.tokenMode |
|
|
|
|
}) |
|
|
|
|
console.log('尝试连接WebSocket URL:', this.url) |
|
|
|
|
|
|
|
|
|
@ -94,8 +120,27 @@ class WebSocketClient { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
try { |
|
|
|
|
console.log(`正在建立WebSocket连接 (尝试 ${this.reconnectAttempts + 1}/${this.maxReconnectAttempts})`) |
|
|
|
|
console.log(`正在建立WebSocket连接${this.tokenMode} (尝试 ${this.reconnectAttempts + 1}/${this.maxReconnectAttempts})`) |
|
|
|
|
|
|
|
|
|
// 根据token模式创建WebSocket连接
|
|
|
|
|
if (this.tokenMode === 'header') { |
|
|
|
|
// header模式: 使用WebSocket子协议传递token
|
|
|
|
|
// 注意:JavaScript WebSocket API要求子协议名必须是有效的字符串,不能包含特殊字符
|
|
|
|
|
// 后端应从Sec-WebSocket-Protocol请求头中获取token信息
|
|
|
|
|
const token = getToken() |
|
|
|
|
if (token) { |
|
|
|
|
// 在token前面加上'token-'前缀
|
|
|
|
|
// 使用简洁的子协议名称,让后端从请求头中解析完整token
|
|
|
|
|
this.ws = new WebSocket(this.url, ['auth-token']) |
|
|
|
|
console.log('WebSocket连接将通过Sec-WebSocket-Protocol头传递token') |
|
|
|
|
} else { |
|
|
|
|
console.error('无法获取token,使用普通连接') |
|
|
|
|
this.ws = new WebSocket(this.url) |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
// url或message模式: 直接创建连接
|
|
|
|
|
this.ws = new WebSocket(this.url) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 设置事件监听
|
|
|
|
|
this.ws.onopen = this.onOpen.bind(this) |
|
|
|
|
@ -114,6 +159,20 @@ class WebSocketClient { |
|
|
|
|
console.log('WebSocket连接已建立') |
|
|
|
|
this.connected = true |
|
|
|
|
this.reconnectAttempts = 0 |
|
|
|
|
|
|
|
|
|
// message模式: 连接成功后发送token
|
|
|
|
|
if (this.tokenMode === 'message') { |
|
|
|
|
const token = getToken() |
|
|
|
|
if (token) { |
|
|
|
|
const authMessage = { |
|
|
|
|
type: 'auth', |
|
|
|
|
token: `token-${token}`, // 在token前面加上'token-'前缀
|
|
|
|
|
userId: this.userId |
|
|
|
|
} |
|
|
|
|
this.send(authMessage) |
|
|
|
|
console.log('已发送认证消息:', authMessage) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 接收消息回调
|
|
|
|
|
@ -135,7 +194,7 @@ class WebSocketClient { |
|
|
|
|
title: message.title || '系统通知', |
|
|
|
|
message: message.content, |
|
|
|
|
type: 'info', |
|
|
|
|
duration: 10000, // 10秒后自动关闭
|
|
|
|
|
duration: 1000000, // 10秒后自动关闭
|
|
|
|
|
showClose: true, |
|
|
|
|
onClick: () => { |
|
|
|
|
// 可以在这里添加点击通知后的处理逻辑
|
|
|
|
|
@ -188,9 +247,17 @@ class WebSocketClient { |
|
|
|
|
console.log(`WebSocket将在 ${Math.round(currentInterval/1000)} 秒后进行第${this.reconnectAttempts}次重连...`) |
|
|
|
|
|
|
|
|
|
setTimeout(() => { |
|
|
|
|
// 重连前刷新token参数
|
|
|
|
|
if (this.url && this.userId) { |
|
|
|
|
this.url = this.url.replace(/token=[^&]*/, `token=${token}`) |
|
|
|
|
// 根据不同token模式更新认证信息
|
|
|
|
|
if (this.tokenMode === 'url' && this.url) { |
|
|
|
|
// URL模式: 更新URL中的token参数
|
|
|
|
|
// 在token前面加上'token-'前缀
|
|
|
|
|
this.url = this.url.replace(/token=[^&]*/, `token=token-${token}`) |
|
|
|
|
} else if (this.tokenMode === 'header') { |
|
|
|
|
// Header模式: 重连时会自动从getToken()获取最新token
|
|
|
|
|
console.log('Header模式下重连,将使用最新token') |
|
|
|
|
} else if (this.tokenMode === 'message') { |
|
|
|
|
// Message模式: 重连成功后会自动发送认证消息
|
|
|
|
|
console.log('Message模式下重连,将在连接建立后发送认证消息') |
|
|
|
|
} |
|
|
|
|
this.connect() |
|
|
|
|
}, currentInterval) |
|
|
|
|
|