- 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连接问题诊断和解决方案
287 lines
9.6 KiB
JavaScript
287 lines
9.6 KiB
JavaScript
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); |