You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 13:35:33