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

React+MongoDB+Express部署后WebSocket连接失败问题求助

用户认证功能部署后登录失败问题

问题详情

本地开发时用户认证(注册、登录)功能正常,但部署到Heroku域名环境后出现错误:

WebSocketClient.js:16 WebSocket connection to 'my_domain' failed:

环境信息

  • 前端:React.js
  • 部署平台:Heroku
  • 服务器端口:4000(本地)
  • 登录成功跳转目标:/Cards页面

相关代码

服务器index.js

const express = require("express");
const cors = require("cors");
const mongoose = require("mongoose");
const authRoutes = require("./Routes/AuthRoutes");
const app = express();
const cookieParser = require("cookie-parser");
require("dotenv").config();

app.listen(4000, () => {
  console.log("Sever started on 4000");
});

mongoose.set("strictQuery", false);

mongoose
  .connect(process.env.DB_URL, {
    useNewUrlParser: true,
    useUnifiedTopology: true,
  })
  .then(() => {
    console.log("Successfully connected to MongoDB Atlas!");
  })
  .catch((err) => {
    console.log(err.message);
  });

app.use(
  cors({
    origin: [
      "http://localhost:3000",
    ],
    method: ["GET", "POST"],
    credentials: true,
  })
);

app.use(cookieParser());
app.use(express.json());
app.use("/", authRoutes);

登录页Login.js

import React, { useState, useEffect } from "react";
import axios from "axios";
import { Link, useNavigate } from "react-router-dom";
import { useCookies } from "react-cookie";
import { ToastContainer, toast } from "react-toastify";
import "../Login.css";

function Login() {
  const [cookies] = useCookies([]);
  const navigate = useNavigate();
  useEffect(() => {
    if (cookies.jwt) {
      navigate("/Cards");
    }
  }, [cookies, navigate]);

  const [values, setValues] = useState({ email: "", password: "" });
  const generateError = (error) =>
    toast.error(error, {
      position: "bottom-right",
    });
  const handleSubmit = async (event) => {
    event.preventDefault();
    try {
      const { data } = await axios.post(
        "http://localhost:4000/login",
        {
          ...values,
        },
        { withCredentials: true }
      );
      if (data) {
        if (data.errors) {
          const { email, password } = data.errors;
          if (email) generateError(email);
          else if (password) generateError(password);
        } else {
          navigate("/Cards");
        }
      }
    } catch (ex) {
      console.log(ex);
    }
  };

问题原因及解决步骤

1. 硬编码API地址导致请求错误

Login.js中登录请求地址写死为http://localhost:4000/login,部署到线上后,前端会尝试访问用户本地的4000端口,而非Heroku服务器地址。

  • 解决:用环境变量存储API地址。在React项目根目录创建.env文件:
    REACT_APP_API_URL=https://你的Heroku应用域名.herokuapp.com
    
    然后修改Login.js中的请求地址:
    await axios.post(
      `${process.env.REACT_APP_API_URL}/login`,
      { ...values },
      { withCredentials: true }
    )
    

2. CORS配置未包含生产域名

服务器CORS仅允许http://localhost:3000的请求,线上前端域名不在白名单中,跨域请求被拦截,进而触发WebSocket相关错误(若有实时通信依赖)。

  • 解决:将Heroku前端域名添加到CORS的origin列表,注意原代码中method应为复数methods:
    app.use(
      cors({
        origin: [
          "http://localhost:3000",
          "https://你的Heroku应用域名.herokuapp.com"
        ],
        methods: ["GET", "POST"],
        credentials: true,
      })
    );
    
    更灵活的方式是用环境变量配置:在Heroku后台设置ALLOWED_ORIGINS为http://localhost:3000,https://你的Heroku应用域名.herokuapp.com,然后修改服务器代码:
    const allowedOrigins = process.env.ALLOWED_ORIGINS.split(",");
    app.use(cors({
      origin: allowedOrigins,
      methods: ["GET", "POST"],
      credentials: true
    }));
    

3. Heroku端口固定配置错误

Heroku会动态分配端口,代码中app.listen(4000)会导致服务器无法正常启动。

  • 解决:使用Heroku提供的PORT环境变量:
    const PORT = process.env.PORT || 4000;
    app.listen(PORT, () => {
      console.log(`Server started on ${PORT}`);
    });
    

4. WebSocket连接排查

错误提示为WebSocket连接失败,需确认:

  • 是否项目中确实使用了WebSocket(如Socket.io),若是则需确保服务器和客户端均使用正确域名,且CORS配置允许WebSocket跨域;
  • 若未使用WebSocket,检查是否有依赖库意外触发了WebSocket连接,可通过浏览器开发者工具的Network面板定位请求来源。

内容的提问来源于stack exchange,提问作者Leo

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 10:05:22