Browse Source

修复临时会话ID解析问题,支持前端格式temp_[currentUserId]_[targetId]_[timestamp]

pull/1/head
Default User 3 months ago
parent
commit
a992ff45bd
  1. 166
      server-example/server-mysql.js
  2. 284
      server-example/test_message_storage.js

166
server-example/server-mysql.js

@ -6253,48 +6253,55 @@ wss.on('connection', (ws, req) => {
return; return;
} }
// 处理聊天消息 // 处理创建会话请求
if (data.type === 'chat_message') { if (data.type === 'create_conversation') {
console.log('接收到聊天消息:', JSON.stringify(data)); console.log('接收到创建会话请求:', JSON.stringify(data));
try {
// 从前端嵌套格式中提取payload const { userId, managerId, timestamp } = data;
let payload = data.data || data.payload || data;
// 构建完整的payload对象,合并顶层和嵌套数据
const completePayload = {
...payload,
// 从顶层data复制重要字段
direction: data.direction || payload.direction || 'customer_to_service',
messageType: data.messageType || payload.messageType || 'text',
// 确保必要的ID字段存在
userId: payload.senderId || payload.userId,
receiverId: payload.receiverId,
// 确保消息内容存在
content: payload.content || '',
contentType: payload.contentType || 1,
timestamp: payload.timestamp || Date.now()
};
// 关键修复:正确映射ID字段 // 验证必要参数
// 对于用户发送给客服的消息,receiverId就是managerId if (!userId || !managerId) {
if (completePayload.receiverId && !completePayload.managerId) { console.error('错误: 创建会话缺少必要参数');
completePayload.managerId = completePayload.receiverId; ws.send(JSON.stringify({
console.log('已将receiverId映射为managerId:', completePayload.managerId); type: 'error',
message: '创建会话失败: 缺少用户ID或客服ID'
}));
return;
} }
// 转换senderType从字符串到数字(确保兼容) // 创建或获取会话
if (typeof completePayload.senderType === 'string') { const conversation = await createOrGetConversation(userId, managerId);
if (completePayload.senderType === 'customer' || completePayload.senderType === 'user') { console.log('会话创建成功:', conversation);
completePayload.senderType = 1; // 普通用户
} else if (completePayload.senderType === 'customer_service' || completePayload.senderType === 'manager') { // 返回会话创建成功响应
completePayload.senderType = 2; // 客服 ws.send(JSON.stringify({
type: 'conversation_created',
conversationId: conversation.conversation_id,
userId: conversation.userId,
managerId: conversation.managerId,
status: conversation.status,
timestamp: timestamp || Date.now()
}));
} catch (error) {
console.error('创建会话失败:', error);
ws.send(JSON.stringify({
type: 'error',
message: '创建会话失败: ' + error.message
}));
} }
console.log('已转换senderType:', completePayload.senderType); return;
} }
// 处理聊天消息
if (data.type === 'chat_message') {
console.log('接收到聊天消息:', JSON.stringify(data));
// 直接使用接收到的数据作为payload,确保格式正确
const payload = data;
// 确保必要字段都已设置 // 确保必要字段都已设置
if (!completePayload.userId) { if (!payload.senderId && !payload.userId) {
console.error('错误: 缺少userId字段'); console.error('错误: 缺少用户ID字段');
ws.send(JSON.stringify({ ws.send(JSON.stringify({
type: 'error', type: 'error',
message: '消息缺少用户ID' message: '消息缺少用户ID'
@ -6302,11 +6309,32 @@ wss.on('connection', (ws, req) => {
return; return;
} }
console.log('处理聊天消息 - 完整payload:', JSON.stringify(completePayload)); // 确保senderType是数字类型
if (payload.senderType && typeof payload.senderType === 'string') {
if (payload.senderType.includes('customer') || payload.senderType.includes('user')) {
payload.senderType = 1; // 普通用户
} else if (payload.senderType.includes('service') || payload.senderType.includes('manager')) {
payload.senderType = 2; // 客服
}
} else if (!payload.senderType) {
// 设置默认值
const connection = connections.get(ws.connectionId);
if (connection && connection.isManager) {
payload.senderType = 2;
} else {
payload.senderType = 1;
}
}
// 确保所有数字字段都是数字类型
payload.senderType = Number(payload.senderType);
payload.contentType = Number(payload.contentType || 1);
console.log('处理聊天消息 - 准备传递的payload:', JSON.stringify(payload));
// 调用handleChatMessage处理消息 // 调用handleChatMessage处理消息
try { try {
await handleChatMessage(ws, completePayload); await handleChatMessage(ws, payload);
console.log('消息处理完成'); console.log('消息处理完成');
} catch (error) { } catch (error) {
console.error('处理聊天消息时出错:', error); console.error('处理聊天消息时出错:', error);
@ -6552,11 +6580,15 @@ async function handleAuth(ws, data) {
let stringManagerId; let stringManagerId;
if (managerId) { if (managerId) {
stringManagerId = String(managerId).trim(); stringManagerId = String(managerId).trim();
} else if (userId) {
// 如果没有提供managerId但提供了userId,尝试使用userId作为managerId
stringManagerId = String(userId).trim();
console.log(`⚠️ 客服认证使用userId作为managerId: ${stringManagerId}`);
} else { } else {
// 缺少必要的managerId // 缺少必要的managerId或userId
ws.send(JSON.stringify({ ws.send(JSON.stringify({
type: 'auth_error', type: 'auth_error',
message: '客服认证失败:缺少必要的managerId' message: '客服认证失败:缺少必要的managerId或userId'
})); }));
return; return;
} }
@ -7048,16 +7080,70 @@ async function handleChatMessage(ws, payload) {
} else { } else {
// 获取会话信息以确定接收者 // 获取会话信息以确定接收者
console.log('查询现有会话:', { conversationId }); console.log('查询现有会话:', { conversationId });
// 检查是否是临时会话ID
if (conversationId && conversationId.startsWith('temp_')) {
console.log('检测到临时会话ID,需要创建真实会话:', conversationId);
// 从临时会话ID中提取信息
// 支持前端临时会话ID格式: temp_[currentUserId]_[targetId]_[timestamp]
const tempIdParts = conversationId.split('_');
if (tempIdParts.length >= 4) {
// 根据连接类型确定正确的userId和managerId
let tempUserId, tempManagerId;
if (connection.isUser) {
// 用户连接: currentUserId是用户ID,targetId是客服ID
tempUserId = tempIdParts[1];
tempManagerId = tempIdParts[2];
} else if (connection.isManager) {
// 客服连接: currentUserId是客服ID,targetId是用户ID
tempManagerId = tempIdParts[1];
tempUserId = tempIdParts[2];
} else {
// 默认情况,尝试判断哪个是用户ID哪个是客服ID
if (tempIdParts[1].includes('user_')) {
tempUserId = tempIdParts[1];
tempManagerId = tempIdParts[2];
} else {
tempUserId = tempIdParts[2];
tempManagerId = tempIdParts[1];
}
}
console.log('从临时ID提取信息:', { tempManagerId, tempUserId });
// 创建或获取真实会话
conversation = await createOrGetConversation(tempUserId, tempManagerId);
console.log('创建的真实会话:', conversation);
receiverId = tempManagerId;
} else {
console.error('无法解析临时会话ID:', conversationId);
throw new Error('无效的临时会话ID格式');
}
} else {
// 正常查询现有会话
const [conversations] = await sequelize.query( const [conversations] = await sequelize.query(
'SELECT * FROM chat_conversations WHERE conversation_id = ?', 'SELECT * FROM chat_conversations WHERE conversation_id = ?',
{ replacements: [conversationId] } { replacements: [conversationId] }
); );
if (!conversations || conversations.length === 0) { if (!conversations || conversations.length === 0) {
throw new Error('会话不存在'); console.warn('会话不存在,尝试从userId和managerId创建');
// 尝试从payload中获取managerId
if (payload.managerId) {
receiverId = validateManagerId(payload.managerId);
console.log('尝试使用payload中的managerId创建会话:', { userId: senderId, managerId: receiverId });
conversation = await createOrGetConversation(senderId, receiverId);
} else {
throw new Error('会话不存在且无法确定客服ID');
} }
} else {
conversation = conversations[0]; conversation = conversations[0];
console.log('查询到的会话详情:', conversation); console.log('查询到的会话详情:', conversation);
receiverId = conversation.managerId; receiverId = conversation.managerId;
}
}
// 验证会话的userId是否与当前用户匹配,不匹配则修复 // 验证会话的userId是否与当前用户匹配,不匹配则修复
if (conversation.userId !== senderId) { if (conversation.userId !== senderId) {

284
server-example/test_message_storage.js

@ -0,0 +1,284 @@
const WebSocket = require('ws');
const readline = require('readline');
const mysql = require('mysql2/promise');
// 数据库连接配置
const dbConfig = {
host: 'localhost',
user: 'root',
password: '123456',
database: 'wechat_app'
};
// 测试配置
const TEST_CONFIG = {
wsUrl: 'ws://localhost:3003',
testUserId: 'test_user_' + Date.now(),
testManagerId: '22',
testMessage: '这是一条测试消息 ' + Date.now()
};
// 创建命令行交互界面
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
// WebSocket测试客户端
class WebSocketTestClient {
constructor() {
this.ws = null;
this.authenticated = false;
this.messages = [];
this.connectionAttempts = 0;
this.maxAttempts = 3;
}
connect(serverUrl = TEST_CONFIG.wsUrl) {
console.log(`正在连接到服务器: ${serverUrl}`);
this.connectionAttempts++;
this.ws = new WebSocket(serverUrl);
this.ws.on('open', () => {
console.log('✅ WebSocket连接已建立');
this.connectionAttempts = 0; // 重置连接尝试次数
this.authenticate();
});
this.ws.on('message', (data) => {
try {
const message = JSON.parse(data.toString());
console.log('📨 收到消息:', JSON.stringify(message, null, 2));
this.handleMessage(message);
} catch (error) {
console.error('❌ 解析消息失败:', error);
}
});
this.ws.on('error', (error) => {
console.error('❌ WebSocket错误:', error.message);
});
this.ws.on('close', (code, reason) => {
console.log(`🔌 WebSocket连接已关闭: ${code} - ${reason}`);
this.authenticated = false;
// 如果不是主动关闭,尝试重连
if (this.connectionAttempts < this.maxAttempts) {
console.log(`尝试重连 (${this.connectionAttempts}/${this.maxAttempts})...`);
setTimeout(() => this.connect(serverUrl), 2000);
}
});
}
authenticate() {
console.log('正在发送认证信息...');
const authMessage = {
type: 'auth',
userId: TEST_CONFIG.testUserId,
userType: 'user',
timestamp: Date.now()
};
console.log('🔑 发送认证请求:', JSON.stringify(authMessage));
this.sendMessage(authMessage);
}
handleMessage(message) {
// 存储接收到的消息
this.messages.push(message);
if (message.type === 'auth_success') {
console.log('✅ 认证成功!');
this.authenticated = true;
this.sendTestMessage();
} else if (message.type === 'auth_error') {
console.error('❌ 认证失败:', message.message);
} else if (message.type === 'message_sent') {
console.log('✅ 消息发送成功确认:', message.payload);
console.log('消息ID:', message.payload.messageId);
console.log('会话ID:', message.payload.conversationId);
} else if (message.type === 'new_message') {
console.log('📥 收到新消息:', message.payload);
this.messages.push(message.payload);
} else if (message.type === 'error') {
console.error('❌ 收到错误消息:', message.message);
}
}
// 数据库查询函数
async queryDatabase() {
let connection = null;
try {
console.log('\n🔍 查询数据库验证消息存储...');
connection = await mysql.createConnection(dbConfig);
// 查询最新消息
const [messages] = await connection.execute(
`SELECT * FROM chat_messages
ORDER BY created_at DESC
LIMIT 5`
);
if (messages.length > 0) {
console.log(`\n📊 找到 ${messages.length} 条最新消息:`);
let testMessageFound = false;
messages.forEach((msg, index) => {
console.log(`\n--- 消息 ${index + 1} ---`);
console.log(`消息ID: ${msg.message_id}`);
console.log(`会话ID: ${msg.conversation_id}`);
console.log(`发送者ID: ${msg.sender_id}`);
console.log(`内容: ${msg.content}`);
if (msg.content === TEST_CONFIG.testMessage) {
console.log('✅ 测试消息已成功存储到数据库!');
testMessageFound = true;
}
});
if (!testMessageFound) {
console.log('\n⚠️ 未找到测试消息');
}
} else {
console.log('\n❌ 未找到任何消息记录');
}
// 查询最新会话
const [conversations] = await connection.execute(
`SELECT * FROM chat_conversations
ORDER BY created_at DESC
LIMIT 5`
);
if (conversations.length > 0) {
console.log(`\n📋 找到 ${conversations.length} 条最新会话:`);
conversations.forEach((conv, index) => {
console.log(`\n--- 会话 ${index + 1} ---`);
console.log(`会话ID: ${conv.conversation_id}`);
console.log(`用户ID: ${conv.userId}`);
console.log(`客服ID: ${conv.managerId}`);
});
}
} catch (error) {
console.error('\n❌ 数据库查询失败:', error.message);
} finally {
if (connection) {
await connection.end();
}
}
}
sendTestMessage() {
// 生成临时会话ID(前端格式: temp_[currentUserId]_[targetId]_[timestamp])
const timestamp = Date.now();
const tempConversationId = `temp_${TEST_CONFIG.testUserId}_${TEST_CONFIG.testManagerId}_${timestamp}`;
console.log(`📝 生成的临时会话ID: ${tempConversationId}`);
const testMessage = {
type: 'chat_message',
conversationId: tempConversationId,
receiverId: TEST_CONFIG.testManagerId,
senderId: TEST_CONFIG.testUserId,
senderType: 1,
content: TEST_CONFIG.testMessage,
contentType: 1,
messageId: 'test_msg_' + Date.now(),
timestamp: Date.now()
};
console.log('📤 发送测试消息:', JSON.stringify(testMessage));
this.sendMessage(testMessage);
// 发送后自动查询数据库验证
setTimeout(() => {
this.queryDatabase().catch(console.error);
}, 2000);
}
testDatabaseStorage() {
console.log('\n=======================================');
console.log('📊 测试数据库存储功能');
console.log('将自动查询数据库验证消息存储');
console.log('=======================================\n');
// 自动查询数据库
this.queryDatabase().catch(console.error);
// 询问用户是否要发送更多消息
this.promptForMoreMessages();
}
promptForMoreMessages() {
rl.question('是否发送另一条测试消息?(y/n): ', (answer) => {
if (answer.toLowerCase() === 'y') {
this.sendTestMessage();
} else {
console.log('\n测试完成!按Ctrl+C退出。');
}
});
}
sendMessage(message) {
if (this.ws && this.ws.readyState === WebSocket.OPEN) {
this.ws.send(JSON.stringify(message));
} else {
console.error('❌ WebSocket未连接,无法发送消息');
}
}
close() {
if (this.ws) {
this.ws.close();
}
rl.close();
}
}
// 自动测试函数
async function autoTest() {
console.log('\n========================================');
console.log('开始自动测试消息存储功能');
console.log('========================================\n');
const client = new WebSocketTestClient();
// 重写handleMessage以支持自动测试
const originalHandleMessage = client.handleMessage.bind(client);
client.handleMessage = function(message) {
originalHandleMessage(message);
if (message.type === 'message_sent') {
// 消息发送成功后查询数据库
setTimeout(() => {
client.queryDatabase().then(() => {
console.log('\n========================================');
console.log('自动测试完成');
console.log('========================================');
process.exit(0);
});
}, 2000);
}
};
client.connect();
}
// 启动测试客户端
console.log('=======================================');
console.log('🚀 消息存储测试工具');
console.log('这个工具将测试WebSocket连接、认证和消息存储功能');
console.log('=======================================\n');
// 自动模式运行
console.log('🎯 以自动测试模式运行...');
autoTest();
// 处理进程终止
process.on('SIGINT', () => {
console.log('\n正在关闭连接...');
process.exit(0);
});
Loading…
Cancel
Save