在 nginx 中,后端获取客户端协议的标准做法是配置 proxy_set_header x-forwarded-proto $scheme;。nginx 会将当前请求使用的协议(如 http 或 https)赋值给 $scheme 变量,并通过该 http 头传递给后端应用。后端代码只需读取 x-forwarded-proto 头的值即可准确判断客户端与 nginx 之间的连接协议。

如何验证 Nginx 是否正确传递了协议头
要验证 Nginx 是否成功将协议传递给后端,最直接的方法是检查后端接收到的 X-Forwarded-Proto 头部内容。当客户端通过 HTTPS 访问时,Nginx 的 $scheme 变量值为 https,此时后端应收到 X-Forwarded-Proto: https;若客户端通过 HTTP 访问,则后端应收到 X-Forwarded-Proto: http。这种机制依赖于 Nginx 作为反向代理时正确解析上游连接属性。

server {
listen 443 ssl;
server_name example.com;
ssl_certificate /etc/nginx/ssl/cert.pem;
ssl_certificate_key /etc/nginx/ssl/key.pem;
location / {
proxy_pass http://backend_app;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
上述配置展示了典型的 HTTPS 终止场景。当客户端通过 https://example.com 发起请求时,Nginx 处理 SSL 解密后,内部转发给 backend_app 的请求中会包含 X-Forwarded-Proto: https。如果客户端使用 http://example.com 访问,且 Nginx 同时监听 80 端口并配置相同逻辑,则后端将收到 X-Forwarded-Proto: http。后端应用可通过读取此头部来构建正确的重定向 URL 或生成安全链接。
为什么不能直接使用后端连接的协议
后端服务通常运行在 Nginx 之后,两者之间通过 HTTP 通信。即使客户端使用 HTTPS,Nginx 到后端的连接往往是 HTTP(除非配置了 upstream SSL)。因此,后端直接检测自身监听协议的 socket 会得到 http,这与客户端实际使用的协议不符。必须依赖 Nginx 显式传递的 X-Forwarded-Proto 头才能获知真实情况。

# Python Flask 示例:获取客户端协议
from flask import request
def get_client_protocol():
# 优先检查 X-Forwarded-Proto
proto = request.headers.get('X-Forwarded-Proto')
if proto:
return proto
# 回退到默认值
return 'http'
这段 Python 代码演示了后端如何安全地获取协议。它首先查询 X-Forwarded-Proto 头,如果存在则返回其值;否则回退到默认值。这种写法兼容了直接访问后端和经过 Nginx 代理两种场景。注意,某些框架如 Django 或 Rails 会自动识别 X-Forwarded-Proto 并设置 request.scheme,开发者可直接使用框架提供的 API 而无需手动解析头部。
基于 proxy_set_header 配置的具体问题:当后端需要强制 HTTPS 时如何处理
当后端应用需要强制所有流量走 HTTPS 时,它必须依据 X-Forwarded-Proto 的值来判断是否进行重定向。如果该头为 http,后端应返回 301 重定向至 https:// 地址;如果为 https,则正常响应。这一逻辑完全依赖于 Nginx 是否正确设置了 proxy_set_header X-Forwarded-Proto $scheme;。若遗漏此配置,后端将无法区分客户端原始协议,可能导致无限重定向循环或安全警告。


















