基于Sails JS和React JS的Socket实时竞价系统问题求助
解决Socket.io跨域连接失败+实时竞价消息同步问题
问题核心诊断
当前代码存在几个关键问题导致连接失败、消息无法接收:
- 跨域配置缺失:前后端端口不同(7039/3637),Sails服务端未配置Socket.io的跨域支持,客户端无法建立连接
- 服务端广播时机错误:当前在新客户端连接时就广播消息,而非商品价格更新的业务触发点
- 客户端连接状态判断逻辑错误:
socket.connected是同步属性,刚调用connect时连接还未建立,会返回false - 广播逻辑未绑定到实际业务场景:没有在商品价格更新的代码处触发消息推送
分步修复方案
1. 配置Sails服务端跨域支持
在Sails的config/sockets.js中添加Socket.io跨域配置:
module.exports.sockets = { transports: ['polling', 'websocket'], cors: { origin: "http://localhost:3637", // 允许你的React客户端域名 credentials: true } };
同时更新config/cors.js确保HTTP请求跨域也被允许:
module.exports.cors = { origin: "http://localhost:3637", credentials: true, methods: "GET, POST, PUT, DELETE, OPTIONS, HEAD" };
2. 修正服务端广播逻辑
将广播代码从连接事件中移出,绑定到商品价格更新的业务方法中,确保只有价格变化时才推送消息:
方案一:使用Sails原生房间广播(推荐)
先让客户端连接时加入指定房间,再在价格更新时推送:
// BidUpdateController.js sails.io.on("connection", (socket) => { console.log("SOCKET ID : "+socket.id); // 让新客户端加入bidUpdate房间 socket.join('bidUpdate'); socket.on('disconnect', () => { console.log('User disconnected'); }); }); // 在商品价格更新的Controller方法中(比如ProductController.updatePrice) async updatePrice(req, res) { // 执行价格更新逻辑 const updatedProduct = await Product.updateOne({ id: req.params.id }) .set({ bidPrice: req.body.bidPrice }); // 向所有在bidUpdate房间的客户端广播更新消息 await sails.sockets.broadcast('bidUpdate', { type: 'PRICE_UPDATED', product: updatedProduct // 携带更新后的商品数据 }); return res.ok(updatedProduct); }
方案二:使用Socket.io原生全局广播
如果不需要房间分组,直接向所有连接客户端推送:
// 在商品价格更新的Controller方法中 async updatePrice(req, res) { const updatedProduct = await Product.updateOne({ id: req.params.id }) .set({ bidPrice: req.body.bidPrice }); // 向所有已连接客户端广播 sails.io.emit('bidUpdate', { type: 'PRICE_UPDATED', product: updatedProduct }); return res.ok(updatedProduct); }
3. 修复客户端连接与消息监听逻辑
修正React客户端代码,正确监听连接状态和消息:
import io from 'socket.io-client'; import React, { useEffect, useState } from 'react'; const BidList = () => { const [bidData, setBidData] = useState([]); useEffect(() => { const connectionOptions = { reconnectionAttempts: Infinity, timeout: 20000, transports: ['polling', 'websocket'] }; const socket = io('http://localhost:7039', connectionOptions); // 监听连接成功事件 socket.on('connect', () => { console.log("SOCKET CONNECTION : " + socket.connected); // 此时返回true }); // 监听价格更新消息 socket.on('bidUpdate', (data) => { console.log("收到价格更新: ", data); // 更新表格数据:根据返回的商品ID匹配更新 setBidData(prevList => prevList.map(item => item.id === data.product.id ? {...item, bidPrice: data.product.bidPrice} : item ) ); }); // 监听连接错误,方便排查问题 socket.on('connect_error', (err) => { console.error("Socket连接失败: ", err); }); return () => { socket.disconnect(); }; }, []); return ( <table> {/* 渲染竞价表格逻辑 */} <thead> <tr> <th>商品名称</th> <th>基础价格</th> <th>当前竞价</th> </tr> </thead> <tbody> {bidData.map(item => ( <tr key={item.id}> <td>{item.name}</td> <td>{item.basePrice}</td> <td>{item.bidPrice}</td> </tr> ))} </tbody> </table> ); }; export default BidList;
额外注意事项
- 移除客户端的
"force new connection": true:该配置会强制创建新连接,容易导致连接不稳定,无特殊需求无需设置 - 确保Socket.io版本匹配:服务端与客户端使用相同大版本(如均为v4),版本不匹配会导致连接失败
- 调试时查看浏览器Network面板:检查WebSocket或Polling请求的状态,排查跨域或连接错误
内容的提问来源于stack exchange,提问作者Tushar Donda
相关产品推荐
相关产品推荐

