后端生成http链接是因Nginx代理后未透传原始协议,须在location块中配置proxy_set_header X-Forwarded-Proto $scheme,并确保后端框架显式信任该头且限定可信IP,否则协议识别失效。

后端生成的链接总是以 http:// 开头,不是因为代码写错了,而是它根本“看不见”用户实际走的是 HTTPS。Nginx 作为反向代理,默认用 HTTP 和后端通信,后端只收到 http 协议的请求,自然就按 http 拼 URL。要让整个链路都感知到 HTTPS,关键不是改后端,而是用 proxy_set_header 把原始协议信息准确、可信地传下去。
必须配置 X-Forwarded-Proto $scheme
这是最核心的一行:
- 加在
location块里,紧挨着proxy_pass前面,不能放在server或http块顶层 - 用
$scheme变量——它由 Nginx 自动识别当前请求是http还是https(取决于listen 443 ssl这类配置) - 绝对不要硬写成
https,否则 HTTP 请求也会被标记为 HTTPS,引发重定向死循环
前有 CDN 时要透传,别覆盖
如果 Nginx 前还有一层(比如 Cloudflare、阿里云 SLB),它们通常已设置 X-Forwarded-Proto:
⚠️ 已弃用 — 该技能已拆分为两个独立技能,以提升模块化程度:**webchat-https-proxy**(HTTPS/WSS 反向代理)和 **webchat-voi...**
- 此时不应再用
proxy_set_header X-Forwarded-Proto $scheme,否则会把 CDN 已填好的值覆盖掉 - 应改用
proxy_set_header X-Forwarded-Proto $http_x_forwarded_proto,原样透传上游值 - 同时确认 CDN 确实开启了该头转发(Cloudflare 默认开启,但需检查 Page Rules 或 WAF 设置)
后端必须显式信任这个头
Nginx 写了没用,后端不认就是白搭。各主流框架需主动启用并限定可信来源:
- Django:设
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https'),并确保USE_X_FORWARDED_HOST = True - Flask:用
ProxyFix,例如app.wsgi_app = ProxyFix(app.wsgi_app, x_proto=1),且只信任内网 IP(如127.0.0.1) - Spring Boot:设
server.forward-headers-strategy=framework,配合server.tomcat.protocol-header=x-forwarded-proto - Node.js(Express):
app.set('trust proxy', '127.0.0.1'),之后req.protocol才返回https
验证是否真正生效
别只看配置文件有没有这行,要从后端输出反推:
- 在后端加日志打印原始 header:
req.headers['x-forwarded-proto'](Node)或request.META.get('HTTP_X_FORWARDED_PROTO')(Django),HTTPS 访问时必须输出https - 用
curl -I https://yoursite.com/login查看响应头中的Location,必须是https://开头,不能是http:// - 检查 Cookie 是否带
Secure标志——只有协议识别正确,框架才会自动加上

















