forked from datawhale/whale-town-end
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连接问题诊断和解决方案
This commit is contained in:
311
full_diagnosis.js
Normal file
311
full_diagnosis.js
Normal file
@@ -0,0 +1,311 @@
|
||||
const io = require('socket.io-client');
|
||||
const https = require('https');
|
||||
const http = require('http');
|
||||
|
||||
console.log('🔍 全面WebSocket连接诊断');
|
||||
console.log('='.repeat(60));
|
||||
|
||||
// 1. 测试基础网络连接
|
||||
async function testBasicConnection() {
|
||||
console.log('\n1️⃣ 测试基础HTTPS连接...');
|
||||
|
||||
return new Promise((resolve) => {
|
||||
const options = {
|
||||
hostname: 'whaletownend.xinghangee.icu',
|
||||
port: 443,
|
||||
path: '/',
|
||||
method: 'GET',
|
||||
timeout: 10000
|
||||
};
|
||||
|
||||
const req = https.request(options, (res) => {
|
||||
console.log(`✅ HTTPS连接成功 - 状态码: ${res.statusCode}`);
|
||||
console.log(`📋 服务器: ${res.headers.server || '未知'}`);
|
||||
resolve({ success: true, statusCode: res.statusCode });
|
||||
});
|
||||
|
||||
req.on('error', (error) => {
|
||||
console.log(`❌ HTTPS连接失败: ${error.message}`);
|
||||
resolve({ success: false, error: error.message });
|
||||
});
|
||||
|
||||
req.on('timeout', () => {
|
||||
console.log('❌ HTTPS连接超时');
|
||||
req.destroy();
|
||||
resolve({ success: false, error: 'timeout' });
|
||||
});
|
||||
|
||||
req.end();
|
||||
});
|
||||
}
|
||||
|
||||
// 2. 测试本地服务器
|
||||
async function testLocalServer() {
|
||||
console.log('\n2️⃣ 测试本地服务器...');
|
||||
|
||||
const testPaths = [
|
||||
'http://localhost:3000/',
|
||||
'http://localhost:3000/socket.io/?EIO=4&transport=polling'
|
||||
];
|
||||
|
||||
for (const url of testPaths) {
|
||||
console.log(`🧪 测试: ${url}`);
|
||||
|
||||
await new Promise((resolve) => {
|
||||
const urlObj = new URL(url);
|
||||
const options = {
|
||||
hostname: urlObj.hostname,
|
||||
port: urlObj.port,
|
||||
path: urlObj.pathname + urlObj.search,
|
||||
method: 'GET',
|
||||
timeout: 5000
|
||||
};
|
||||
|
||||
const req = http.request(options, (res) => {
|
||||
console.log(` 状态码: ${res.statusCode}`);
|
||||
if (res.statusCode === 200) {
|
||||
console.log(' ✅ 本地服务器正常');
|
||||
} else {
|
||||
console.log(` ⚠️ 本地服务器响应: ${res.statusCode}`);
|
||||
}
|
||||
resolve();
|
||||
});
|
||||
|
||||
req.on('error', (error) => {
|
||||
console.log(` ❌ 本地服务器连接失败: ${error.message}`);
|
||||
resolve();
|
||||
});
|
||||
|
||||
req.on('timeout', () => {
|
||||
console.log(' ❌ 本地服务器超时');
|
||||
req.destroy();
|
||||
resolve();
|
||||
});
|
||||
|
||||
req.end();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 3. 测试远程Socket.IO路径
|
||||
async function testRemoteSocketIO() {
|
||||
console.log('\n3️⃣ 测试远程Socket.IO路径...');
|
||||
|
||||
const testPaths = [
|
||||
'/socket.io/?EIO=4&transport=polling',
|
||||
'/game/socket.io/?EIO=4&transport=polling',
|
||||
'/socket.io/?transport=polling',
|
||||
'/api/socket.io/?EIO=4&transport=polling'
|
||||
];
|
||||
|
||||
const results = [];
|
||||
|
||||
for (const path of testPaths) {
|
||||
console.log(`🧪 测试路径: ${path}`);
|
||||
|
||||
const result = await new Promise((resolve) => {
|
||||
const options = {
|
||||
hostname: 'whaletownend.xinghangee.icu',
|
||||
port: 443,
|
||||
path: path,
|
||||
method: 'GET',
|
||||
timeout: 8000,
|
||||
headers: {
|
||||
'User-Agent': 'socket.io-diagnosis'
|
||||
}
|
||||
};
|
||||
|
||||
const req = https.request(options, (res) => {
|
||||
console.log(` 状态码: ${res.statusCode}`);
|
||||
|
||||
let data = '';
|
||||
res.on('data', (chunk) => {
|
||||
data += chunk;
|
||||
});
|
||||
|
||||
res.on('end', () => {
|
||||
if (res.statusCode === 200) {
|
||||
console.log(' ✅ 路径可用');
|
||||
console.log(` 📄 响应: ${data.substring(0, 50)}...`);
|
||||
} else {
|
||||
console.log(` ❌ 路径不可用: ${res.statusCode}`);
|
||||
}
|
||||
resolve({ path, statusCode: res.statusCode, success: res.statusCode === 200 });
|
||||
});
|
||||
});
|
||||
|
||||
req.on('error', (error) => {
|
||||
console.log(` ❌ 请求失败: ${error.message}`);
|
||||
resolve({ path, error: error.message, success: false });
|
||||
});
|
||||
|
||||
req.on('timeout', () => {
|
||||
console.log(' ❌ 请求超时');
|
||||
req.destroy();
|
||||
resolve({ path, error: 'timeout', success: false });
|
||||
});
|
||||
|
||||
req.end();
|
||||
});
|
||||
|
||||
results.push(result);
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
// 4. 测试Socket.IO客户端连接
|
||||
async function testSocketIOClient() {
|
||||
console.log('\n4️⃣ 测试Socket.IO客户端连接...');
|
||||
|
||||
const configs = [
|
||||
{
|
||||
name: 'HTTPS + 所有传输方式',
|
||||
url: 'https://whaletownend.xinghangee.icu',
|
||||
options: { transports: ['websocket', 'polling'], timeout: 10000 }
|
||||
},
|
||||
{
|
||||
name: 'HTTPS + 仅Polling',
|
||||
url: 'https://whaletownend.xinghangee.icu',
|
||||
options: { transports: ['polling'], timeout: 10000 }
|
||||
},
|
||||
{
|
||||
name: 'HTTPS + /game namespace',
|
||||
url: 'https://whaletownend.xinghangee.icu/game',
|
||||
options: { transports: ['polling'], timeout: 10000 }
|
||||
}
|
||||
];
|
||||
|
||||
const results = [];
|
||||
|
||||
for (const config of configs) {
|
||||
console.log(`🧪 测试: ${config.name}`);
|
||||
console.log(` URL: ${config.url}`);
|
||||
|
||||
const result = await new Promise((resolve) => {
|
||||
const socket = io(config.url, config.options);
|
||||
let resolved = false;
|
||||
|
||||
const timeout = setTimeout(() => {
|
||||
if (!resolved) {
|
||||
resolved = true;
|
||||
socket.disconnect();
|
||||
console.log(' ❌ 连接超时');
|
||||
resolve({ success: false, error: 'timeout' });
|
||||
}
|
||||
}, config.options.timeout);
|
||||
|
||||
socket.on('connect', () => {
|
||||
if (!resolved) {
|
||||
resolved = true;
|
||||
clearTimeout(timeout);
|
||||
console.log(' ✅ 连接成功');
|
||||
console.log(` 📡 Socket ID: ${socket.id}`);
|
||||
console.log(` 🚀 传输方式: ${socket.io.engine.transport.name}`);
|
||||
socket.disconnect();
|
||||
resolve({ success: true, transport: socket.io.engine.transport.name });
|
||||
}
|
||||
});
|
||||
|
||||
socket.on('connect_error', (error) => {
|
||||
if (!resolved) {
|
||||
resolved = true;
|
||||
clearTimeout(timeout);
|
||||
console.log(` ❌ 连接失败: ${error.message}`);
|
||||
resolve({ success: false, error: error.message });
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
results.push({ config: config.name, ...result });
|
||||
|
||||
// 等待1秒再测试下一个
|
||||
await new Promise(resolve => setTimeout(resolve, 1000));
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
// 5. 检查DNS解析
|
||||
async function testDNS() {
|
||||
console.log('\n5️⃣ 检查DNS解析...');
|
||||
|
||||
const dns = require('dns');
|
||||
|
||||
return new Promise((resolve) => {
|
||||
dns.lookup('whaletownend.xinghangee.icu', (err, address, family) => {
|
||||
if (err) {
|
||||
console.log(`❌ DNS解析失败: ${err.message}`);
|
||||
resolve({ success: false, error: err.message });
|
||||
} else {
|
||||
console.log(`✅ DNS解析成功: ${address} (IPv${family})`);
|
||||
resolve({ success: true, address, family });
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// 主诊断函数
|
||||
async function runFullDiagnosis() {
|
||||
console.log('开始全面诊断...\n');
|
||||
|
||||
try {
|
||||
const dnsResult = await testDNS();
|
||||
const basicResult = await testBasicConnection();
|
||||
await testLocalServer();
|
||||
const socketIOPaths = await testRemoteSocketIO();
|
||||
const clientResults = await testSocketIOClient();
|
||||
|
||||
console.log('\n' + '='.repeat(60));
|
||||
console.log('📊 诊断结果汇总');
|
||||
console.log('='.repeat(60));
|
||||
|
||||
console.log(`1. DNS解析: ${dnsResult.success ? '✅ 正常' : '❌ 失败'}`);
|
||||
if (dnsResult.address) {
|
||||
console.log(` IP地址: ${dnsResult.address}`);
|
||||
}
|
||||
|
||||
console.log(`2. HTTPS连接: ${basicResult.success ? '✅ 正常' : '❌ 失败'}`);
|
||||
if (basicResult.error) {
|
||||
console.log(` 错误: ${basicResult.error}`);
|
||||
}
|
||||
|
||||
const workingPaths = socketIOPaths.filter(r => r.success);
|
||||
console.log(`3. Socket.IO路径: ${workingPaths.length}/${socketIOPaths.length} 个可用`);
|
||||
workingPaths.forEach(p => {
|
||||
console.log(` ✅ ${p.path}`);
|
||||
});
|
||||
|
||||
const workingClients = clientResults.filter(r => r.success);
|
||||
console.log(`4. Socket.IO客户端: ${workingClients.length}/${clientResults.length} 个成功`);
|
||||
workingClients.forEach(c => {
|
||||
console.log(` ✅ ${c.config} (${c.transport})`);
|
||||
});
|
||||
|
||||
console.log('\n💡 建议:');
|
||||
|
||||
if (!dnsResult.success) {
|
||||
console.log('❌ DNS解析失败 - 检查域名配置');
|
||||
} else if (!basicResult.success) {
|
||||
console.log('❌ 基础HTTPS连接失败 - 检查服务器状态和防火墙');
|
||||
} else if (workingPaths.length === 0) {
|
||||
console.log('❌ 所有Socket.IO路径都不可用 - 检查nginx配置和后端服务');
|
||||
} else if (workingClients.length === 0) {
|
||||
console.log('❌ Socket.IO客户端无法连接 - 可能是CORS或协议问题');
|
||||
} else {
|
||||
console.log('✅ 部分功能正常 - 使用可用的配置继续开发');
|
||||
|
||||
if (workingClients.length > 0) {
|
||||
const bestConfig = workingClients.find(c => c.transport === 'websocket') || workingClients[0];
|
||||
console.log(`💡 推荐使用: ${bestConfig.config}`);
|
||||
}
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('诊断过程中发生错误:', error);
|
||||
}
|
||||
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
runFullDiagnosis();
|
||||
Reference in New Issue
Block a user