Node.js + Express 搭建 CORS 跨域服务:5分钟配置 3个关键响应头

Node.js + Express 实战配置 CORS 跨域服务的 5 个关键步骤

跨域资源共享(CORS)是现代 Web 开发中无法回避的技术挑战。作为后端开发者,我们需要为前端应用提供安全且灵活的 API 接口支持。本文将带你从零开始,通过 Express 框架快速构建支持 CORS 的 Node.js 服务,并深入解析每个配置参数的实际意义。

1. 初始化 Express 项目与基础配置

首先创建一个全新的 Node.js 项目并安装 Express:

mkdir cors-demo && cd cors-demo npm init -y npm install express

创建基础服务器文件server.js

const 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.com
Access-Control-Allow-Methods允许的 HTTP 方法GET, POST, PUT
Access-Control-Allow-Headers允许的请求头Content-Type, X-Requested-With

3. 处理预检请求(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));

常见陷阱与解决方案:

  1. 通配符与凭证冲突
    当设置credentials: true时,origin不能使用*,必须指定具体域名。

  2. Vary 头的重要性
    对于动态判断源的情况,应添加Vary: Origin头避免 CDN 缓存问题:

    app.use((req, res, next) => { res.vary('Origin'); next(); });
  3. 复杂请求处理
    对于 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 防护体系。