Files
whale-town-end/test_websocket_handshake_redirect.js
moyin 38f9f81b6c test:添加WebSocket连接诊断和测试工具集
- test_zulip.js: Zulip集成功能的端到端测试脚本
- full_diagnosis.js: 全面的WebSocket连接诊断工具
- test_protocol_difference.js: 不同协议(ws/wss/http/https)的对比测试
- test_redirect_and_websocket.js: HTTP重定向和WebSocket升级测试
- test_websocket_handshake_redirect.js: WebSocket握手重定向机制验证
- websocket_with_redirect_support.js: 支持重定向的WebSocket连接实现

提供完整的WebSocket连接问题诊断和解决方案
2026-01-05 11:16:52 +08:00

287 lines
9.6 KiB
JavaScript
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
const https = require('https');
const http = require('http');
const io = require('socket.io-client');
console.log('🔍 详细测试WebSocket握手重定向机制');
console.log('='.repeat(60));
// 1. 手动模拟WebSocket握手请求 - HTTP阶段
async function testWebSocketHandshakeHTTP() {
console.log('\n1⃣ 测试WebSocket握手的HTTP阶段...');
return new Promise((resolve) => {
console.log('📡 发送WebSocket握手请求到 HTTP (80端口)');
const options = {
hostname: 'whaletownend.xinghangee.icu',
port: 80,
path: '/socket.io/?EIO=4&transport=websocket',
method: 'GET',
headers: {
'Upgrade': 'websocket',
'Connection': 'Upgrade',
'Sec-WebSocket-Key': 'dGhlIHNhbXBsZSBub25jZQ==',
'Sec-WebSocket-Version': '13',
'Origin': 'http://whaletownend.xinghangee.icu',
'User-Agent': 'websocket-handshake-test'
},
timeout: 10000
};
const req = http.request(options, (res) => {
console.log(`📊 HTTP响应状态码: ${res.statusCode}`);
console.log('📋 响应头:');
Object.entries(res.headers).forEach(([key, value]) => {
console.log(` ${key}: ${value}`);
});
let data = '';
res.on('data', (chunk) => {
data += chunk;
});
res.on('end', () => {
if (data && data.length < 500) {
console.log(`📄 响应内容: ${data}`);
}
console.log('\n📊 分析结果:');
if (res.statusCode === 301 || res.statusCode === 302) {
console.log('✅ WebSocket握手请求被重定向');
console.log(`🔄 重定向到: ${res.headers.location}`);
console.log('💡 证明: WebSocket握手的HTTP阶段支持重定向');
} else if (res.statusCode === 101) {
console.log('✅ WebSocket握手成功升级');
} else if (res.statusCode === 400) {
console.log('❌ WebSocket握手失败 - 400错误');
} else {
console.log(`⚠️ 意外的响应: ${res.statusCode}`);
}
resolve({
statusCode: res.statusCode,
location: res.headers.location,
isRedirect: res.statusCode === 301 || res.statusCode === 302
});
});
});
req.on('error', (error) => {
console.log(`❌ HTTP请求失败: ${error.message}`);
resolve({ error: error.message });
});
req.on('timeout', () => {
console.log('❌ HTTP请求超时');
req.destroy();
resolve({ error: 'timeout' });
});
req.end();
});
}
// 2. 测试Socket.IO客户端是否能自动处理重定向
async function testSocketIORedirectHandling() {
console.log('\n2⃣ 测试Socket.IO客户端重定向处理...');
const testConfigs = [
{
name: 'WS协议 - 测试重定向',
url: 'ws://whaletownend.xinghangee.icu/game',
options: {
transports: ['websocket'],
timeout: 8000,
forceNew: true
}
},
{
name: 'HTTP协议 - 测试重定向',
url: 'http://whaletownend.xinghangee.icu/game',
options: {
transports: ['websocket', 'polling'],
timeout: 8000,
forceNew: true
}
}
];
const results = [];
for (const config of testConfigs) {
console.log(`\n🧪 ${config.name}`);
console.log(`📡 URL: ${config.url}`);
const result = await new Promise((resolve) => {
const socket = io(config.url, config.options);
let resolved = false;
// 监听连接事件
socket.on('connect', () => {
if (!resolved) {
resolved = true;
console.log(' ✅ 连接成功');
console.log(` 📡 Socket ID: ${socket.id}`);
console.log(` 🚀 传输方式: ${socket.io.engine.transport.name}`);
console.log(` 🔗 最终URL: ${socket.io.uri}`);
// 检查是否发生了协议升级
const originalProtocol = config.url.startsWith('ws://') ? 'ws' : 'http';
const finalProtocol = socket.io.uri.startsWith('wss://') ? 'wss' :
socket.io.uri.startsWith('ws://') ? 'ws' :
socket.io.uri.startsWith('https://') ? 'https' : 'http';
if (originalProtocol !== finalProtocol) {
console.log(` 🔄 协议升级: ${originalProtocol}:// → ${finalProtocol}://`);
}
socket.disconnect();
resolve({
success: true,
transport: socket.io.engine.transport.name,
finalUrl: socket.io.uri,
protocolChanged: originalProtocol !== finalProtocol
});
}
});
socket.on('connect_error', (error) => {
if (!resolved) {
resolved = true;
console.log(` ❌ 连接失败: ${error.message}`);
console.log(` 🔍 错误类型: ${error.type || 'unknown'}`);
// 检查是否是重定向相关的错误
if (error.message.includes('redirect') || error.message.includes('301') || error.message.includes('302')) {
console.log(' 💡 这可能是重定向处理问题');
}
resolve({
success: false,
error: error.message,
type: error.type
});
}
});
// 超时处理
setTimeout(() => {
if (!resolved) {
resolved = true;
socket.disconnect();
console.log(' ❌ 连接超时');
resolve({ success: false, error: 'timeout' });
}
}, config.options.timeout);
});
results.push({ config: config.name, ...result });
// 等待1秒再测试下一个
await new Promise(resolve => setTimeout(resolve, 1000));
}
return results;
}
// 3. 测试不同客户端库的重定向行为
async function testRawWebSocketRedirect() {
console.log('\n3⃣ 测试原生WebSocket重定向行为...');
const WebSocket = require('ws');
return new Promise((resolve) => {
console.log('📡 使用原生WebSocket连接 ws://whaletownend.xinghangee.icu/socket.io/?EIO=4&transport=websocket');
try {
const ws = new WebSocket('ws://whaletownend.xinghangee.icu/socket.io/?EIO=4&transport=websocket');
ws.on('open', () => {
console.log(' ✅ 原生WebSocket连接成功');
console.log(' 💡 说明: 重定向在WebSocket握手阶段被正确处理');
ws.close();
resolve({ success: true });
});
ws.on('error', (error) => {
console.log(` ❌ 原生WebSocket连接失败: ${error.message}`);
if (error.message.includes('Unexpected server response: 301') ||
error.message.includes('Unexpected server response: 302')) {
console.log(' 💡 发现重定向响应但WebSocket库未自动处理');
console.log(' 📝 说明: 需要客户端库支持重定向处理');
}
resolve({ success: false, error: error.message });
});
ws.on('close', (code, reason) => {
console.log(` 🔌 WebSocket关闭: ${code} - ${reason}`);
});
} catch (error) {
console.log(` ❌ WebSocket创建失败: ${error.message}`);
resolve({ success: false, error: error.message });
}
});
}
async function runHandshakeRedirectTests() {
console.log('开始WebSocket握手重定向测试...\n');
const httpResult = await testWebSocketHandshakeHTTP();
const socketIOResults = await testSocketIORedirectHandling();
const rawWSResult = await testRawWebSocketRedirect();
console.log('\n' + '='.repeat(60));
console.log('📊 WebSocket握手重定向测试结果');
console.log('='.repeat(60));
console.log(`1. WebSocket握手HTTP阶段: ${httpResult.isRedirect ? '✅ 支持重定向' : '❌ 无重定向'}`);
if (httpResult.location) {
console.log(` 重定向目标: ${httpResult.location}`);
}
console.log(`2. Socket.IO客户端处理:`);
socketIOResults.forEach((result, index) => {
const status = result.success ? '✅ 成功' : '❌ 失败';
console.log(` ${index + 1}. ${result.config}: ${status}`);
if (result.protocolChanged) {
console.log(` 协议升级: 是`);
}
if (result.error) {
console.log(` 错误: ${result.error}`);
}
});
console.log(`3. 原生WebSocket: ${rawWSResult.success ? '✅ 成功' : '❌ 失败'}`);
if (rawWSResult.error) {
console.log(` 错误: ${rawWSResult.error}`);
}
console.log('\n💡 技术原理验证:');
if (httpResult.isRedirect) {
console.log('✅ 验证: WebSocket握手的HTTP阶段确实支持重定向');
console.log('📝 机制: ws://先发HTTP GET请求(带Upgrade头) → 收到301/302 → 可以重定向');
} else {
console.log('❌ 未检测到WebSocket握手重定向');
}
const successfulSocketIO = socketIOResults.filter(r => r.success);
if (successfulSocketIO.length > 0) {
console.log('✅ Socket.IO客户端能够处理某些重定向场景');
} else {
console.log('❌ Socket.IO客户端无法处理当前的重定向配置');
}
console.log('\n🔧 修正后的准确表述:');
console.log('1. ✅ HTTP请求(包括WebSocket握手请求)支持301/302重定向');
console.log('2. ✅ WebSocket的"升级请求(HTTP层)"可以被重定向');
console.log('3. ✅ ws://先通过80端口发HTTP握手请求再尝试升级为WebSocket');
console.log('4. ⚠️ 客户端库需要支持重定向处理才能正常工作');
process.exit(0);
}
runHandshakeRedirectTests().catch(console.error);