Heroku部署Express配置CORS仍报预检跨域错误的解决方法
本地托管无校验逻辑的简易ReactJS CRUD表单项目,后端为部署在Heroku平台的NodeJS Express服务,尝试开启CORS跨域支持时,所有常规配置都无法为预检请求正确设置响应头,浏览器返回如下错误:
Access to XMLHttpRequest at 'https://cors-be.herokuapp.com/api/user/create' from origin 'http://localhost:3000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
排查过程中已排除以下干扰因素:
- 项目初始
index.js已按官方文档配置cors中间件,代码如下:
const express = require('express') const cors = require('cors') const app = express() app.use(cors()) app.use(express.json()) app.options("*", cors()) // 首次排查新增的OPTIONS请求处理配置 app.get("/", (req, res) => { res.json({message: "API is listening"}) }) const userRouter = require("./api/user/router") app.use("/api/user", userRouter) app.listen(5432, () => { console.log(`Server is listening on port 5432`) })
package.json中安装的cors依赖版本为"cors": "^2.8.5",不存在版本兼容问题- 经Chrome、Firefox、Edge多浏览器测试均复现问题,排除浏览器特定兼容问题
- 本地运行服务时所有跨域功能正常,排除接口业务代码导致错误的可能
- 针对预检请求为OPTIONS方法的特性,补充
app.options("*", cors())配置统一处理所有OPTIONS请求,核心配置如下,但修改后跨域问题仍未解决:
const express = require('express') const cors = require('cors') const app = express() app.use(cors()) app.use(express.json()) app.options("*", cors())
该问题与CORS配置本身无关,核心原因是服务监听端口被硬编码为5432。Heroku平台部署规则要求应用必须监听process.env.PORT环境变量指定的动态端口,平台路由层才能将外部请求转发到应用进程。硬编码固定端口时,所有外部请求(包括OPTIONS预检请求)都无法到达Express服务,返回的响应自然不会携带CORS相关响应头,最终触发浏览器跨域报错。
原错误监听代码如下:
app.listen(5432, () => { console.log(`Server is listening on port 5432`) })
修改端口监听逻辑,优先读取Heroku动态分配的process.env.PORT环境变量,本地开发场景下 fallback 到5432端口即可。修改后的监听配置如下:
require("dotenv").config() const PORT = process.env.PORT || 5432 app.listen(PORT, () => { console.log(`Server is listening on port ${PORT}`) })
配置修改后重新部署到Heroku,跨域问题即可解决。
内容的提问来源于stack exchange,提问作者Corey Power

