部署MERN栈至Vercel遇CORS错误,登录后跳转异常
问题:MERN栈部署Vercel后登录跳转异常及CORS错误
我将MERN栈的前后端代码部署至Vercel,注册时前端可正常将邮箱等信息发送至后端并存入MongoDB Atlas在线数据库。但使用注册凭证登录时,验证通过后页面刚加载到下一页就跳回登录页,控制台出现如下CORS错误:
Access to fetch at 'https://swap-ease-now-backend.vercel.app/details' from origin 'https://swap-ease-now.vercel.app' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'. Details.js:9 GET https://swap-ease-now-backend.vercel.app/details net::ERR_FAILED (anonymous) @ Details.js:9 f @ regeneratorRuntime.js:44 (anonymous) @ regeneratorRuntime.js:125 (anonymous) @ regeneratorRuntime.js:69 Be @ asyncToGenerator.js:3 o @ asyncToGenerator.js:22 (anonymous) @ asyncToGenerator.js:27 (anonymous) @ asyncToGenerator.js:19 (anonymous) @ Details.js:7 (anonymous) @ Details.js:32 as @ react-dom.production.min.js:244 ku @ react-dom.production.min.js:286 (anonymous) @ react-dom.production.min.js:282 w @ scheduler.production.min.js:13 P @ scheduler.production.min.js:14 Details.js:27 TypeError: Failed to fetch at Details.js:9:25 at f (regeneratorRuntime.js:44:17) at Generator.<anonymous> (regeneratorRuntime.js:125:22) at Generator.next (regeneratorRuntime.js:69:21) at Be (asyncToGenerator.js:3:20) at o (asyncToGenerator.js:22:9) at asyncToGenerator.js:27:7 at new Promise (<anonymous>) at asyncToGenerator.js:19:12 at Details.js:7:20
我不确定错误源于Cookie、Token还是CORS,因为若为CORS问题,注册时的前端数据也无法提交至后端。以下是后端的代码:
app.js
const dotenv=require("dotenv"); const mongoose=require('mongoose'); const express=require('express'); const app=express(); const cors = require('cors'); dotenv.config({path: './config.env'}); const User=require('./models/userSchema'); require('./db/conn.js'); app.use(express.json()); app.use(cors()); // to link the router file to route the path easily app.use(require('./router/auth')); const PORT=process.env.PORT || 5000; app.get('/signup',(req,res)=> { res.send('Hello at signup'); }) app.listen(PORT,()=> { console.log(`running at port number ${PORT}`); })
auth.js(路由文件)
const jwt=require("jsonwebtoken"); const express=require('express'); const router=express.Router(); const bcrypt=require('bcryptjs'); const authenticate=require("../middleware/authenticate"); const fs = require("fs"); const path = require("path"); require('../db/conn'); const User=require('../models/userSchema'); const cookieParser = require("cookie-parser"); const cors = require("cors"); const Authenticate = require("../middleware/authenticate"); router.use(cookieParser()); router.use(cors()); //login route router.post('/signin',async (req,res)=> { res.header('Access-Control-Allow-Origin', '*'); res.header('Access-Control-Allow-Methods', 'POST'); res.header('Access-Control-Allow-Headers', 'Content-Type'); try { let token; const {email,password}=req.body; if(!email || !password) { return res.status(400).json({error:"Either one or more fields are empty...."}); } const userLogin=await User.findOne({email:email}); if(userLogin) { const isMatch=await bcrypt.compare(password,userLogin.password); token=await userLogin.generateAuthToken(); console.log(token); res.cookie("jwtoken",token,{ expires: new Date(Date.now()+ 25892000000), httpOnly:true }); if(!isMatch) { res.status(400).json({error:"Invalid user credentials...."}); } else{ res.json({message:"Successful"}); } } else { res.status(400).json({error:"Invalid user credentials...."}); } } catch(err){ console.log(err); } } ) router.get('/details', authenticate,(req,res)=> { res.send(req.rootUser); })
问题根源
错误提示明确:当请求的credentials模式为include时,Access-Control-Allow-Origin不能使用通配符*。登录时后端设置了HttpOnly Cookie(jwtoken),前端请求/details接口时会自动携带该Cookie,此时请求的credentials模式为include,但后端CORS配置使用了通配符*,导致预请求失败,/details接口无法返回用户数据,前端鉴权逻辑因拿不到数据触发跳转,回到登录页。
注册时未触发此问题,是因为注册接口没有携带Cookie,请求的credentials模式为same-origin,通配符*可以正常工作。
修复步骤
- 全局配置CORS(替换app.js中的
app.use(cors());)
不要使用默认的通配符,指定允许的前端域名,同时开启凭证支持:app.use(cors({ origin: process.env.FRONTEND_URL, // 例如"https://swap-ease-now.vercel.app",建议存在.env环境变量中 credentials: true })); - 清理auth.js中的冗余配置
- 删除
router.use(cors());,全局已配置CORS,无需重复设置 - 删除
signin接口中手动设置的res.header三行代码,cors中间件会自动处理跨域头
- 删除
- 确保前端请求携带凭证
前端调用/details的请求需开启凭证携带:- Fetch示例:
fetch('https://swap-ease-now-backend.vercel.app/details', { credentials: 'include' }) - Axios示例:
axios.get('https://swap-ease-now-backend.vercel.app/details', { withCredentials: true })
- Fetch示例:
- Vercel部署配置
后端部署到Vercel时,需在项目环境变量中添加FRONTEND_URL,值为你的前端域名,确保CORS配置生效。
内容的提问来源于stack exchange,提问作者Aman Kakkar
相关产品推荐
相关产品推荐

