Node.js + Express 搭建 CORS 跨域服务:5分钟配置 3个关键响应头
Node.js Express 实战配置 CORS 跨域服务的 5 个关键步骤跨域资源共享CORS是现代 Web 开发中无法回避的技术挑战。作为后端开发者我们需要为前端应用提供安全且灵活的 API 接口支持。本文将带你从零开始通过 Express 框架快速构建支持 CORS 的 Node.js 服务并深入解析每个配置参数的实际意义。1. 初始化 Express 项目与基础配置首先创建一个全新的 Node.js 项目并安装 Expressmkdir cors-demo cd cors-demo npm init -y npm install express创建基础服务器文件server.jsconst express require(express); const app express(); const PORT 3000; // 基础路由 app.get(/, (req, res) { res.send(欢迎来到 CORS 服务); }); app.listen(PORT, () { console.log(服务运行在 http://localhost:${PORT}); });此时如果前端尝试从不同端口访问这个接口浏览器会阻止请求并抛出跨域错误。这正是我们需要解决的典型场景。2. 手动配置核心 CORS 响应头Express 允许我们通过中间件手动设置响应头来解决跨域问题。以下是三个最关键的响应头app.get(/api/data, (req, res) { // 允许特定源访问生产环境应替换为实际前端地址 res.setHeader(Access-Control-Allow-Origin, http://localhost:8080); // 允许的 HTTP 方法 res.setHeader(Access-Control-Allow-Methods, GET, POST, OPTIONS); // 允许的请求头 res.setHeader(Access-Control-Allow-Headers, Content-Type, Authorization); res.json({ message: 跨域请求成功 }); });关键参数解析响应头作用示例值Access-Control-Allow-Origin指定允许访问的源*或http://example.comAccess-Control-Allow-Methods允许的 HTTP 方法GET, POST, PUTAccess-Control-Allow-Headers允许的请求头Content-Type, X-Requested-With3. 处理预检请求OPTIONS对于非简单请求如带自定义头或 PUT/DELETE 方法浏览器会先发送 OPTIONS 预检请求。我们需要专门处理// 专门处理 OPTIONS 预检请求 app.options(/api/data, (req, res) { res.setHeader(Access-Control-Allow-Origin, http://localhost:8080); res.setHeader(Access-Control-Allow-Methods, GET, POST, OPTIONS); res.setHeader(Access-Control-Allow-Headers, Content-Type, Authorization); res.status(204).end(); });4. 使用 cors 中间件简化配置手动设置响应头虽然灵活但繁琐。Express 社区提供了cors中间件来简化这一过程npm install cors基本用法const cors require(cors); // 全局启用 CORS允许所有源 app.use(cors()); // 或者配置特定选项 app.use(cors({ origin: http://localhost:8080, methods: [GET, POST], allowedHeaders: [Content-Type, Authorization], credentials: true // 允许携带凭证如 cookies }));cors 中间件配置选项{ origin: String|Function|Array, // 访问源控制 methods: String|Array, // 允许的 HTTP 方法 allowedHeaders: String|Array, // 允许的请求头 exposedHeaders: String|Array, // 暴露给前端的响应头 credentials: Boolean, // 是否允许凭证 maxAge: Number // 预检请求缓存时间秒 }5. 生产环境最佳实践与安全考量在实际生产环境中我们需要更加严格的 CORS 策略const whitelist [ https://yourdomain.com, https://yourotherdomain.com ]; const corsOptions { origin: (origin, callback) { if (whitelist.indexOf(origin) ! -1 || !origin) { callback(null, true); } else { callback(new Error(不允许的跨域请求)); } }, methods: [GET, POST, PUT, DELETE], allowedHeaders: [Content-Type, Authorization, X-Requested-With], maxAge: 86400 // 24小时 }; app.use(cors(corsOptions));常见陷阱与解决方案通配符与凭证冲突当设置credentials: true时origin不能使用*必须指定具体域名。Vary 头的重要性对于动态判断源的情况应添加Vary: Origin头避免 CDN 缓存问题app.use((req, res, next) { res.vary(Origin); next(); });复杂请求处理对于 PUT/DELETE 或自定义头的请求确保正确处理 OPTIONS 预检请求。完整示例代码以下是整合所有要点的完整实现const express require(express); const cors require(cors); const app express(); // 生产环境域名白名单 const whitelist [ http://localhost:8080, https://yourproductiondomain.com ]; // 动态 CORS 配置 const corsOptions { origin: (origin, callback) { if (whitelist.includes(origin) || !origin) { callback(null, true); } else { callback(new Error(不允许的跨域请求)); } }, methods: [GET, POST, PUT, DELETE, OPTIONS], allowedHeaders: [Content-Type, Authorization, X-Requested-With], credentials: true, maxAge: 86400 }; // 应用 CORS 中间件 app.use(cors(corsOptions)); // 添加 Vary 头 app.use((req, res, next) { res.vary(Origin); next(); }); // 示例 API 路由 app.get(/api/products, (req, res) { res.json([ { id: 1, name: 产品A }, { id: 2, name: 产品B } ]); }); // 带身份验证的示例 app.post(/api/orders, (req, res) { // 实际项目中这里会有验证逻辑 res.json({ orderId: 123, status: created }); }); const PORT process.env.PORT || 3000; app.listen(PORT, () { console.log(CORS 服务已启动端口 ${PORT}); });通过以上配置你的 Express 服务已经具备了完善的跨域支持能力。记住CORS 只是安全策略的一部分实际项目中还应结合其他安全措施如输入验证、速率限制等来构建全面的 API 防护体系。