React+Node.js项目HTTPS域名下非GET请求跨域缺失Allow Origin头报错求助
问题说明
我使用React.js开发前端应用,对接Node.js后端服务。用服务器IP地址在前端调用API时一切正常,切换为域名HTTPS访问后,仅GET请求可正常执行,POST、DELETE、PUT等所有其他请求均无法正常工作。
- Axios执行API请求返回报错栈:
Error: Network Error at n.exports (createError.js:16) at XMLHttpRequest.g.onerror (xhr.js:84)
- 使用fetch发起请求返回报错:
TypeError: Failed to fetch
我已经尝试过两类CORS配置方案,均无效果:
- 手动设置CORS响应头
app.use((req, res, next) => { res.setHeader('Access-Control-Allow-Origin', '*') res.setHeader('Access-Control-Allow-Methods','OPTIONS, GET, POST, PUT, PATCH, DELETE') res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization') next() })
- 使用cors中间件
const cors = require('cors'); app.use(cors())
前端请求示例代码:
await axios.put(`${baseUrl}/users/updateProfil/${id}`, data, { headers: { 'Content-Type': 'application/json' , 'Authorization': `Bearer ${JSON.parse(token)}` } }) .then(res => res.data).catch((e)=>{ alert(e); console.log(e) });
后端用户资料更新接口实现代码:
router.put('/updateProfil/:id', async (req, res) => { var userId = req.params.id; var first_name = req.body.first_name; var last_name = req.body.last_name; var email = req.body.email; var country = req.body.country; var city = req.body.city; var phone = req.body.phone; var sender_sms_name = req.body.sender_sms_name; if ( email && phone && city && country && first_name && last_name && sender_sms_name ) { var user = await User.findOne({ $or: [{ phone: phone }, { email: email }], }).select('-password').catch((error) => { res.status(404).json({ success: false, val: 0, data: "error", message: "Something went wrong.", }); }); if (user != null) { await User.findByIdAndUpdate(userId, { first_name: first_name, email: email, last_name: last_name, phone: phone, city: city, country: country, sender_sms_name: sender_sms_name}, {new: true}) .then( async(user) => { user= await User.populate(user, {path: 'sub_account'}) return res.status(200).json({ success: true, val: 1, data: user, message: "update done ", }); }); }else{ return res.status(404).json({ success: true, val: 1, data: "error while updating", message: "update success ! ", }); } }else { return res.status(404).json({ success: false, val: 0, data: "impossible to update!", message: "verify fields please.", }); } });
解决方案
请按以下优先级逐一排查:
检查反向代理/CDN配置
这是90%以上HTTPS域名切换后非GET请求失败的原因:IP访问时是直接请求Node.js服务,切换域名后大概率走了Nginx、Apache等反向代理或者云CDN,这类服务默认会拦截PUT、DELETE等非通用HTTP方法。- 如果你使用Nginx反向代理,需要在站点配置的
location块中添加允许对应方法的配置,同时直接处理OPTIONS预检请求,无需转发到Node服务:
location / { proxy_pass http://你的Node服务内网地址:端口; proxy_method GET; proxy_method POST; proxy_method PUT; proxy_method DELETE; proxy_method OPTIONS; if ($request_method = OPTIONS ) { add_header Access-Control-Allow-Origin *; add_header Access-Control-Allow-Methods "OPTIONS, GET, POST, PUT, DELETE, PATCH"; add_header Access-Control-Allow-Headers "Content-Type, Authorization"; return 204; } }- 如果你使用了云服务商的CDN、WAF服务,需要到对应控制台配置允许PUT、DELETE等请求方法,部分服务商默认只放行GET、HEAD、POST三种方法。
- 如果你使用Nginx反向代理,需要在站点配置的
检查baseUrl协议配置
确认前端配置的baseUrl是https://开头,不要残留http://,HTTPS站点发起HTTP请求会被浏览器的混合内容策略直接拦截,也会返回网络错误。修复后端预检请求处理逻辑
你当前的手动CORS配置没有单独处理OPTIONS预检请求,非简单请求(带自定义头的PUT、POST等)浏览器会先发送OPTIONS预检请求,你的代码直接把OPTIONS请求转发给了路由,而路由没有对应OPTIONS的处理逻辑,会返回404导致请求失败。可以在手动CORS配置里增加预检请求判断:
app.use((req, res, next) => { res.setHeader('Access-Control-Allow-Origin', '*') res.setHeader('Access-Control-Allow-Methods','OPTIONS, GET, POST, PUT, PATCH, DELETE') res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization') // 预检请求直接返回204 if(req.method === 'OPTIONS') { return res.sendStatus(204) } next() })
注意手动CORS配置和cors中间件不要同时使用,避免配置冲突,二选一即可。
内容的提问来源于stack exchange,提问作者Stephane Biteb
相关产品推荐
相关产品推荐

