本地Angular调用Heroku部署的Node.js API出现CORS策略错误
问题根因排查与解决方案
1. 首先解决跨域配置的逻辑冲突
你当前的跨域头配置存在浏览器规范不允许的冲突:同时设置了Access-Control-Allow-Origin: *和Access-Control-Allow-Credentials: true。根据W3C的跨域规范,带凭证(Cookie、Authorization头等)的跨域请求,不允许Access-Control-Allow-Origin使用通配符*,必须指定明确的允许域名。
2. 调整跨域中间件的配置和顺序
你已经安装了cors依赖,不建议手写跨域中间件,很容易漏处理预检请求,直接用官方依赖的配置更稳妥,且需要把跨域中间件放在所有路由定义的最前面:
const cors = require('cors'); app.use(cors({ // 本地开发填你Angular应用的访问地址,比如http://localhost:4200,生产环境替换为线上前端域名 // 需要支持多个域名可以传数组,或者传入函数做动态匹配 origin: '你的前端应用实际域名', credentials: true, allowedHeaders: ['Origin', 'X-Requested-With', 'Content-Type', 'Accept', 'Authorization'], methods: ['GET', 'POST', 'OPTIONS', 'PUT', 'HEAD', 'PATCH', 'DELETE'] }));
如果坚持要用手写的中间件,需要补充对OPTIONS预检请求的处理,否则Heroku的反向代理可能会拦截预检请求导致跨域头丢失:
app.use(function (req, res, next) { res.setHeader('Access-Control-Allow-Origin', '你的前端应用实际域名'); res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, HEAD,PATCH, DELETE'); res.setHeader('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept, Authorization'); res.setHeader('Access-Control-Allow-Credentials', true); // 单独处理OPTIONS预检请求,直接返回204状态码 if (req.method === 'OPTIONS') { return res.sendStatus(204); } next(); });
3. 优先修复接口的异步逻辑错误
你当前的接口代码存在严重的异步逻辑问题,这才是大概率的触发原因:
- 回调嵌套形成闭包,循环变量的取值错乱,最终拿到的用户信息全是最后一次循环的内容
- 异步数据库查询的完成顺序不确定,用
j++计数的判断逻辑完全不可靠,很容易导致接口报错抛出500状态码
而Heroku默认的500错误页不会携带你自定义的跨域头,浏览器就会优先报CORS错误,掩盖了真实的接口错误问题。
建议用async/await重写接口逻辑,避免回调地狱:
app.get("/getNoOfUsersGuardians", async (request, response) => { try { const _userData = await database.collection("_User").find().toArray(); const userArr = []; for (const user of _userData) { const userId = "_User$" + user._id; const guardianCount = await database.collection("GuardianInvitation").count({ _p_fromUser: userId, status:"accepted" }); if (guardianCount <= 0) continue; const resultdevice = await database.collection("_Session").findOne({_p_user: userId}); if (!resultdevice) continue; userArr.push({ userid: userId, username: user.username, name: user.name, mobileno: user.phoneNumber, userEmail: user.email, phoneCountryCode: user.phoneCountryCode, _updated_at: user._updated_at, NoofGuardian: guardianCount, device: resultdevice.device }); } if(userArr.length > 0){ return response.send({ status: true, data: userArr, message: 'User list found that have Number of guardians' }); } return response.send({ status: false, data: "", message: 'Guardians list not found' }); } catch (error) { return response.status(500).json({ status: false, data: '', message: error.message }); } });
4. 最后排查Heroku运行日志
修改完成后如果还报错,直接查看Heroku的应用运行日志,确认接口请求是否有抛出异常、是否正常返回200状态码,优先解决业务代码的报错后再验证跨域问题。
内容的提问来源于stack exchange,提问作者Ovesh Kazi
相关产品推荐
相关产品推荐

