11 Nginx 与 Express 的 Header 职责
1. 先确定谁产生响应
典型部署:
GET /index.html -> Nginx 读取前端静态文件
GET /assets/app.js -> Nginx 读取静态文件
GET /api/users -> Nginx 反向代理 -> Express
Express 的 helmet() 只能修改经过 Express 的响应。它加在 /api/users JSON 上的 CSP,不会控制早已由 Nginx 返回的 index.html。真正影响页面加载脚本、样式、图片和 Fetch 目标的 CSP,应出现在 HTML 响应上。
2. 推荐职责划分
| 内容 | 常见负责人 | 原因 |
|---|---|---|
| HTML 的 CSP、frame 策略 | 提供 HTML 的 Nginx/前端服务 | 策略必须跟随页面响应 |
| 静态资源缓存、类型 | Nginx | Nginx 直接提供文件 |
| API CORS | Express | 更了解路由、环境和身份模式 |
| HSTS | 最外层 HTTPS Nginx | 它知道客户端连接是否为 HTTPS |
| API 安全 Header | Express Helmet | 与 API/文件路由策略结合 |
| 请求 ID | Nginx 生成或透传,Express 记录 | 便于端到端关联日志 |
这不是绝对规定。重要的是一个 Header 有一个明确所有者,并把职责记录下来。
3. add_header 与 always
Nginx 示例:
add_header X-Content-Type-Options "nosniff" always;
没有 always 时,add_header 只对 Nginx 规定的一组响应状态生效,错误状态可能没有该 Header;always 让它不受响应码限制地添加。它仍不能给“尚未形成 HTTP 响应”的 TLS/网络失败添加 Header。
还要注意 Nginx 配置继承:当前层级只要出现自己的 add_header,上层的 add_header 继承行为可能与直觉不同。修改后应对实际 location 和不同状态码逐个测试。
4. 不要重复设置 CORS
如果 Express 返回:
Access-Control-Allow-Origin: https://www.example.com
Nginx 又添加:
Access-Control-Allow-Origin: *
最终可能形成两个值,浏览器会因响应不合法而拒绝。不要把“再加一遍”当作保险。
建议:
- API CORS 统一交给 Express;
- Nginx 正常透传上游 Header;
- 只有 Nginx 自己产生的错误确需跨源可见时,才设计一套一致策略;
- 若使用
proxy_hide_header隐藏上游 Header,必须明确覆盖规则和风险。
5. Nginx 返回的错误响应
以下响应可能不是 Express 产生的:
413 Request Entity Too Large:Nginx 上传限制;502 Bad Gateway:Express 未启动或上游连接失败;504 Gateway Timeout:上游超时;- Nginx location 不匹配产生的 404;
- TLS/证书错误发生在 HTTP 之前。
即使 Express 的错误处理很完善,这些响应也不会变成 Express JSON。跨源前端还可能因缺少 CORS Header 只看到 CORS 错误。运维监控必须直接检查 HTTP 状态、Nginx error log 和上游状态,不能只依赖前端报错。
6. 同源反向代理通常不需要 CORS
页面:https://example.com/
API:https://example.com/api/
协议、主机、端口都相同,浏览器认为同源。Nginx 虽把 /api 转发到内部 127.0.0.1:8080,内部地址不会改变浏览器看到的 Origin,因此通常不需要 CORS。
如果页面是 https://www.example.com、API 是 https://api.example.com,则为跨源,需要精确配置。
7. HTTPS、代理与 Express
TLS 通常终止在 Nginx,Express 看到的是内部 HTTP。需要 Express 正确识别外部协议、客户端 IP 或 Secure Cookie 时,应限定可信代理:
app.set("trust proxy", 1);
具体值取决于代理层数和网络拓扑,不能不加判断地设为 true。Nginx 应正确传递 X-Forwarded-Proto、X-Forwarded-For 等信息,并阻止外部客户端绕过可信代理直接访问 Express。
8. 如何查明 Header 来自哪里
分别请求公网入口和 Express 本机端口:
curl -ik https://www.example.com/api/users
curl -i http://127.0.0.1:8080/api/users
再增加 Origin 测试:
curl -ik https://www.example.com/api/users \
-H "Origin: https://frontend.example.com"
若仅公网响应多出 Header,通常来自 Nginx/CDN;若两处都有,通常来自 Express 或两层重复配置。还应检查 Nginx 完整生效配置,而不只看单个文件。