后端因CORS策略无法访问Cookie的问题排查与解决
问题描述
基于MERN栈开发React应用,Express+Node.js作为后端,实现Cookie存储JWT的登录系统。前端用axios调用接口,Redux Toolkit管理状态。注册功能正常,但登录时控制台报错:
'The value of the 'Access-Control-Allow-Credentials' header in the response is '' which must be 'true' when the request's credentials mode is 'include'.'
相关代码
前端API配置
const baseURL="http://localhost:8000"; axios.defaults.withCredentials=true; const API=axios.create({ baseURL, }); export const signIn=(formData)=>API.post('/authentication/signin',formData); export const login=(formData)=>API.post('/authentication/login',formData);
Redux Thunk调用代码
export const signup=createAsyncThunk('auth/signup',async({formData},{fulfillWithValue,rejectWithValue})=>{ try{ const response=await api.login(formData); console.log(response.token); return fulfillWithValue(response.token); }catch(err){ rejectWithValue(err.response.data) } })
后端初始CORS设置
app.use(cors())
后端登录处理函数
export const signUser=catchAsync(async(req,res,next)=>{ const email=req.body.email; const password=req.body.password; if(!email||!password){ return next(new ErrorHandling('You did not entered user name or password',404)); } const user=await User.findOne({email}).select('+password'); if(!user||!(await user.correctPassword(password,user.password))){ return next(new ErrorHandling('User name or password are incorrect',400)); } const token=jsonwebtoken.sign({id},process.env.JWT_SECRET,{ expiresIn:process.env.JWT_EXPIRES_IN} ); const cookieOptions={ onlyHttp:true } if(process.env.NODE_ENV=='production'){ cookieOptions.secure=true; cookieOptions.expires=new Date(Date.now()+1000*60) // 1分钟后过期 } res.cookie('jwt',token,cookieOptions); return res.status(statusCode).json({ status:"success", token, data: user }) });
后端index.js初始配置
const app=express(); app.use(express.json()); app.use(bodyParser.urlencoded({extended:false})); app.use(bodyParser.json()); app.use(cookieParser()); app.use(cors()) dotenv.config({path:'./config.env'}) let database=process.env.DATABASE; const port= process.env.PORT||5000 database=process.env.DATABASE.replace('<password>',process.env.DATABASE_PASSWORD); app.use('/post',postRoute); app.use('/user',userRoute); app.use('/authentication',authRoute); app.all('*',(req,res,next)=>{ next(new ErrorHandling("Can't find results check if path is valid",404)); }) app.use(ErrorController) let conn=mongoose.connect(database,{ useNewUrlParser: true, useUnifiedTopology: true }).then(data=>{ if(data){ console.log("Successfully connected to server"); } else{ throw new Error("Unable to connect"); } }).catch(err=>{ console.log(err.message); }) app.listen(port,()=>{ console.log(`Listening to port ${port}`); })
package.json片段
{ "name": "y", "version": "1.0.0", "description": "Social media blog application", "main": "index.js", "type": "module", "proxy": "http://localhost:3000", .......... }
解决方法
起初怀疑是CORS配置未开启凭证支持,尝试修改CORS配置:
app.use(cors({ origin: 'http://localhost:3000', // 匹配前端地址 credentials: true }))
但问题仍未解决。最终排查发现是body-parser中间件的顺序错误。
原配置中body-parser放在了cors之前,导致请求先被解析,CORS头无法正确注入响应。将body-parser移到cors之后,调整后的中间件顺序如下:
const app=express(); // 先配置CORS,确保跨域头正确设置 app.use(cors({ origin: 'http://localhost:3000', credentials: true })); // 再解析请求体 app.use(express.json()); app.use(bodyParser.urlencoded({extended:false})); app.use(bodyParser.json()); app.use(cookieParser()); // 后续路由、数据库连接等代码保持不变
调整后,CORS先处理跨域请求的响应头,确保Access-Control-Allow-Credentials设为true,之后再解析请求体,axios的withCredentials: true也能正常传递Cookie,登录功能正常工作。
内容的提问来源于stack exchange,提问作者Jogn1522
相关产品推荐
相关产品推荐

