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

Vercel部署全栈应用遇CORS跨域错误(状态码204)求助

CORS跨域错误排查:Vercel部署后注册/登录请求失败(Status code:204)

本地全栈应用运行正常,但将前后端部署到Vercel后,点击注册/登录表单提交按钮时,浏览器控制台抛出错误:is not allowed by Access-Control-Allow-Origin. Status code: 204,已排查两天未解决。

错误截图

CORS错误截图

后端注册路由代码

const { firstName, username, age, email, password} = req.body;
console.log("Registration user input:", firstName, username, age, email, password);

try {
  const existingUser = await User.findOne({ username });

  if (existingUser) {
    return res.status(400).json({ message: "Username already taken. Please try a different one." });
  }
  
  const existingEmail = await User.findOne({ email })

  if (existingEmail) {
    return res.status(400).json({ message: "Email already taken. Please try a different one." });
  }

  const salt = await bcrypt.genSalt(10);
  const hashedPassword = await bcrypt.hash(password, salt);

  const newUser = new User({firstName,username,age,email,password: hashedPassword,});

  await newUser.save();

  const token = jwt.sign(
    { id: newUser._id, username: newUser.username },
    process.env.JWT_SECRET!,
    { expiresIn: "1h" }
  );

  res.status(201).json({ message: "User created successfully", token });
} catch (error) {
  console.error(error);
  res.status(500).json({ message: "Something went wrong" });
}
});

前端提交代码

event.preventDefault();
setErrorMessage("");

if (!firstName || firstName.length <= 1) {
  setErrorMessage("First name is required and should be longer than 1 character.");
} else if (!username || username.length <= 4) {
  setErrorMessage("Username is required and should be longer than 4 characters.");
} else if (!age || Number(age) <= 12) {
  setErrorMessage("Age is required and should be more than 12.");
} else if (!email || !email.includes("@")) {
  setErrorMessage("A valid email is required.");
} else if (!password || !/[!@#$%^&*]/.test(password) || password.length <= 8) {
  setErrorMessage("Password is required, should be longer than 8 characters, and contain at least one special character.");
} else if (password !== passwordConfirmation) {
  setErrorMessage("Password confirmation does not match the password.");
} else {
  try {
    //const response = await fetch("http://localhost:3000/api/register", {method: "POST", mode: "cors", headers: { "Content-Type": "application/json" },body: JSON.stringify({ firstName, username, age, email, password })});
    const response = await fetch("https://---------.vercel.app/api/register", { method: "POST", headers: { "Content-Type": "application/json" },body: JSON.stringify({ firstName, username, age, email, password })});
    if (response.ok) {
      console.log("User registered successfully");
      localStorage.setItem("isLoggedIn", "true");
      navigate("/intro");
    } else {
      const data = await response.json();
      setErrorMessage(data.message || "Failed to register user"); 
      console.error("Failed to register user");
    }
  } catch (error) {
    console.error("An error occurred:", error);
  }
}
};

解决方案

1. 配置Vercel全局CORS规则

在后端项目根目录创建vercel.json文件,添加跨域配置:

{
  "headers": [
    {
      "source": "/api/(.*)",
      "headers": [
        { "key": "Access-Control-Allow-Credentials", "value": "true" },
        { "key": "Access-Control-Allow-Origin", "value": "https://your-frontend.vercel.app" }, // 替换为你的前端实际域名
        { "key": "Access-Control-Allow-Methods", "value": "GET,OPTIONS,PATCH,DELETE,POST,PUT" },
        { "key": "Access-Control-Allow-Headers", "value": "Content-Type" }
      ]
    }
  ]
}

配置完成后重新部署后端项目,确保配置生效。

2. 处理OPTIONS预检请求

浏览器发送POST请求前会自动发送OPTIONS预检请求,需要在API路由中明确响应:

// 在注册路由前添加OPTIONS处理
app.options('/api/register', (req, res) => {
  res.setHeader('Access-Control-Allow-Origin', 'https://your-frontend.vercel.app');
  res.setHeader('Access-Control-Allow-Methods', 'POST');
  res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
  res.sendStatus(200);
});

如果使用Next.js API路由,可借助cors包简化处理:

import Cors from 'cors';

const cors = Cors({
  methods: ['POST', 'OPTIONS'],
  origin: 'https://your-frontend.vercel.app',
});

function runMiddleware(req, res, fn) {
  return new Promise((resolve, reject) => {
    fn(req, res, (result) => {
      if (result instanceof Error) return reject(result);
      return resolve(result);
    });
  });
}

export default async function handler(req, res) {
  await runMiddleware(req, res, cors);
  // 原有的注册逻辑...
}

3. 修正前端请求配置

在fetch中明确指定mode: "cors",确保浏览器按跨域规则处理请求:

const response = await fetch("https://your-backend.vercel.app/api/register", { 
  method: "POST", 
  mode: "cors",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ firstName, username, age, email, password })
});

4. 清除Vercel缓存重新部署

Vercel可能缓存旧代码,手动触发后端项目的重新部署,确保新的CORS配置完全生效。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 02:52:32