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

React(Vite)请求Node.js后端登录接口遇CORS跨域错误求助

解决Vite React前端与Node.js后端的CORS跨域问题

问题概述

使用Vite搭建的React前端向基于Node.js+MongoDB的后端发送登录POST请求时,触发CORS跨域错误,提示预检请求未通过,目标资源缺少Access-Control-Allow-Origin响应头。

错误信息

login:1 Access to XMLHttpRequest at 'http://localhost:8800/api/auth/login' from origin 'http://127.0.0.1:5173' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
{
    "message": "Network Error",
    "name": "AxiosError",
    "stack": "AxiosError: Network Error\n    at XMLHttpRequest.handleError (http://127.0.0.1:5173/node_modules/.vite/deps/axios.js?v=b0cda0cd:1440:14)",
    "config": {
        "transitional": {
            "silentJSONParsing": true,
            "forcedJSONParsing": true,
            "clarifyTimeoutError": false
        },
        "adapter": [
            "xhr",
            "http"
        ],
        "transformRequest": [
            null
        ],
        "transformResponse": [
            null
        ],
        "timeout": 0,
        "xsrfCookieName": "XSRF-TOKEN",
        "xsrfHeaderName": "X-XSRF-TOKEN",
        "maxContentLength": -1,
        "maxBodyLength": -1,
        "env": {},
        "headers": {
            "Accept": "application/json, text/plain, */*",
            "Content-Type": "application/json"
        },
        "withCredentials": true,
        "method": "post",
        "url": "http://localhost:8800/api/auth/login",
        "data": "{\"username\":\"as\",\"password\":\"as\"}"
    },
    "code": "ERR_NETWORK",
    "status": null
}
POST http://localhost:8800/api/auth/login net::ERR_FAILED

相关代码

前端Login组件

const Login = () => {
  const [username, setUsername] = useState("");
  const [password, setPassword] = useState("");
  const [error, setError] = useState(false);

  const handleSubmit = async (e) => {
    e.preventDefault();

    try {
      const res = await axios.post(
        "http://localhost:8800/api/auth/login",
        {
          username,
          password,
        },
        {
          withCredentials: true,  
        }
      );
      console.log(res);
    } catch (err) {
      setError(err);
      console.log(error);
      console.log(err);
    }
  };

  return (
    <div className="login">
      <form onSubmit={handleSubmit}>
        <h1>Sign in</h1>
        <label htmlFor="">Username</label>
        <input
          type="text"
          name="username"
          placeholder="ahmed"
          onChange={(e) => setUsername(e.target.value)}
        />

        <label htmlFor="">Password</label>
        <input
          type="password"
          name="password"
          placeholder="password"
          onChange={(e) => setPassword(e.target.value)}
        />

        <button type="submit">Login</button>
      </form>
    </div>
  );
};

后端server.js

const express = require("express");
const mongoose = require("mongoose");
const cookieParser = require("cookie-parser");
const dotenv = require("dotenv");
const userRoute = require("./routes/user.route.js");
const gigRoute = require("./routes/gig.route.js");
const orderRoute = require("./routes/order.route.js");
const messageRoute = require("./routes/message.route.js");
const conversationRoute = require("./routes/conversation.route.js");
const reviewRoute = require("./routes/review.route.js");
const authRoute = require("./routes/auth.route");
const cors = require("cors");

const app = express();

app.use(express.json());
app.use(cookieParser());
dotenv.config();
mongoose.set("strictQuery", true);

function handleError(error) {
  console.error("An error occurred:", error);
}

async function startServer() {
  try {
    await mongoose.connect(process.env.MONGO);
    console.log("conneted!");
  } catch (error) {
    handleError(error);
  }
}

app.use("/api/users", userRoute);
app.use("/api/auth", authRoute);
// app.use("/api/gigs", gigRoute);
// app.use("/api/orders", orderRoute);
// app.use("/api/conversations", conversationRoute);
// app.use("/api/messages", messageRoute);
// app.use("/api/reviews", reviewRoute);

// error handling middleware
app.use((err, req, res, next) => {
  const errorStatus = err.status || 500;
  const errorMessage = err.message || "Something went wrong!";

  return res.status(errorStatus).send(errorMessage);
});

//
app.use( //here i am using cors
  cors({
    origin: "*",
  })
);

app.listen(8800, () => {
  startServer();
  console.log("app is listening at 8800!");
});

后端auth.route.js

const express = require("express");
const { register, login, logout } = require("../controllers/auth.controller");

const router = express.Router();

router.post("/register", register);
router.post("/login", login);
router.post("/logout", logout);

module.exports = router;

后端auth.controller.js

const User = require("../models/user.model");
const bcrypt = require("bcrypt");
const jwt = require("jsonwebtoken");
const { createError } = require("../utils/createError");
const login = async (req, res, next) => {
  try {
    const user = await User.findOne({ username: req.body.username });
    if (!user) return next(createError(404, "user not found!"));

    const isCorrect = bcrypt.compareSync(req.body.password, user.password);
    if (!isCorrect)
      return next(createError(400, "Wrong password or username!"));

    const token = jwt.sign(
      {
        id: user._id, //object id
        isSeller: user.isSeller,
      },
      process.env.JWT_KEY
    );

    const { password, ...info } = user._doc;
    res.header("Access-Control-Allow-Origin", "http://127.0.0.1:5173");
    res
      .cookie("accessToken", token, {
        httpOnly: true,
      })
      .status(200)
      .send(info);

    res.status(200).send(user);
  } catch (err) {
    next(err);
  }
};
const logout = async (req, res) => {
  res
    .clearCookie("accessToken", {
      sameSite: "none",
      secure: true,
    })
    .status(200)
    .send("User has been logged out!");
};
const register = async (req, res, next) => {
  try {
    const hash = bcrypt.hashSync(req.body.password, 5);
    const newUser = new User({ ...req.body, password: hash });
    await newUser.save();
    res.status(201).send("User has been created");
  } catch (err) {
    next(err);
  }
};
module.exports = {
  login,
  logout,
  register,
};

修复方案

1. 调整CORS中间件顺序

Express中间件按注册顺序执行,CORS中间件必须放在路由和错误处理中间件之前,否则预检请求(OPTIONS)无法被正确处理。修改server.js:

// 先注册CORS中间件
app.use(
  cors({
    origin: "http://127.0.0.1:5173", // 匹配前端地址
    credentials: true, // 允许携带Cookie
  })
);

// 再注册路由
app.use("/api/users", userRoute);
app.use("/api/auth", authRoute);

// 最后注册错误处理中间件
app.use((err, req, res, next) => {
  const errorStatus = err.status || 500;
  const errorMessage = err.message || "Something went wrong!";

  return res.status(errorStatus).send(errorMessage);
});

2. 移除重复的响应发送与冗余Header设置

在auth.controller.js的login函数中,res.cookie(...).send(info)已经发送了响应,后面的res.status(200).send(user)会导致"Cannot set headers after they are sent to the client"错误,同时手动设置的CORS Header可由中间件统一处理,直接删除冗余代码:

const login = async (req, res, next) => {
  try {
    const user = await User.findOne({ username: req.body.username });
    if (!user) return next(createError(404, "user not found!"));

    const isCorrect = bcrypt.compareSync(req.body.password, user.password);
    if (!isCorrect)
      return next(createError(400, "Wrong password or username!"));

    const token = jwt.sign(
      {
        id: user._id,
        isSeller: user.isSeller,
      },
      process.env.JWT_KEY
    );

    const { password, ...info } = user._doc;
    // 移除手动设置的CORS Header,由中间件统一处理
    // res.header("Access-Control-Allow-Origin", "http://127.0.0.1:5173");
    res
      .cookie("accessToken", token, {
        httpOnly: true,
        // 开发环境可省略sameSite和secure,生产环境需配置
        // sameSite: "none",
        // secure: true,
      })
      .status(200)
      .send(info);

    // 删除重复的响应发送
    // res.status(200).send(user);
  } catch (err) {
    next(err);
  }
};

3. 可选:使用环境变量管理前端地址

在.env文件中添加前端地址:

FRONTEND_URL=http://127.0.0.1:5173

然后在server.js中引用:

app.use(
  cors({
    origin: process.env.FRONTEND_URL,
    credentials: true,
  })
);

验证修复

重启后端服务,重新触发前端登录请求,CORS错误应该会消失,请求能正常返回数据并设置Cookie。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 17:47:13