已配置CORS仍报错?Node.js+React跨域问题求助
问题场景
我用Node.js+TypeScript搭建了API并配置了CORS,API端配置代码如下:
import cors from 'cors'; const options: cors.CorsOptions = { origin: 'http://localhost:3000', methods: 'GET,HEAD,OPTIONS,PUT,PATCH,POST,DELETE', allowedHeaders: [ 'Origin', 'X-Requested-With', 'Content-Type', 'Accept', 'X-Access-Token', 'access-control-allow-origin', ], credentials: true, preflightContinue: false, }; app.use(cors(options)); app.options('*', cors(options));
同时有一个使用axios的React应用,登录组件代码如下:
import { useState } from 'react' import axios from 'axios' import './Login.css' const Login = () => { const [ email, setEmail] = useState(''); const [ password, setPassword] = useState(''); const handleLogin = async () => { if(email !== '' && password !== ''){ await axios.post('http://localhost:3003/allProducts', {Id: 1}).then((result) => { console.log(result) }) } } return ( <div className='login'> <h1>Login</h1> <form> <input type="email" placeholder='Email' onChange={(e) => setEmail(e.target.value)}/> <input type="password" placeholder='Password' onChange={(e) => setPassword(e.target.value)}/> <button type='button' onClick={handleLogin}>Login</button> </form> <p>Don't have an account yet?<span>Sign in.</span></p> </div> ) } export default Login
已经在API端设置了CORS头,尝试了多种网上的方法,但还是持续收到CORS错误,请问问题出在哪里?
排查与解决思路
1. 跨域源匹配问题
API配置的origin是http://localhost:3000,首先要确认React应用实际运行的端口是否为3000——如果React用了其他端口(比如3001),源地址不匹配会直接触发CORS错误,可通过浏览器地址栏确认端口。
如果需要支持多个源,不要写死单个地址,改成动态判断:
const allowedOrigins = ['http://localhost:3000', 'http://localhost:3001']; // 按需添加 const options: cors.CorsOptions = { origin: (origin, callback) => { if (!origin || allowedOrigins.includes(origin)) { callback(null, true); } else { callback(new Error('Not allowed by CORS')); } }, // 其他配置不变 };
2. 请求头配置冗余与遗漏
access-control-allow-origin是响应头,不是请求头,没必要加到allowedHeaders里,直接删掉这个冗余配置。
另外,打开浏览器开发者工具的Network面板,查看OPTIONS预检请求的Request Headers,如果有不在allowedHeaders列表里的字段,把它们补充进去(比如axios默认携带的Accept-Encoding等)。
3. 凭证模式一致性
API配置了credentials: true,意味着允许携带Cookie、HTTP认证等凭证,但React端的axios请求必须同步开启withCredentials: true,否则浏览器会因凭证模式不匹配报错。修改请求代码:
await axios.post('http://localhost:3003/allProducts', {Id: 1}, { withCredentials: true }).then((result) => { console.log(result) })
也可以全局配置axios:axios.defaults.withCredentials = true;
4. 预检请求处理顺序
确保app.options('*', cors(options))和app.use(cors(options))的代码放在所有路由定义之前,否则OPTIONS请求会先被路由规则拦截,无法正确返回CORS头。
5. 浏览器缓存干扰
浏览器可能会缓存旧的CORS响应,导致新配置不生效。打开开发者工具的Network面板,勾选Disable cache后刷新页面重新测试。
内容的提问来源于stack exchange,提问作者johnjoao_

