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_headeralways

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: *

最终可能形成两个值,浏览器会因响应不合法而拒绝。不要把“再加一遍”当作保险。

建议:

5. Nginx 返回的错误响应

以下响应可能不是 Express 产生的:

即使 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-ProtoX-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 完整生效配置,而不只看单个文件。