bigywater.tech
Flask · 175

ProxyFix 的作用

ProxyFix 的每个参数到底改了什么?子路径部署为什么链接全丢了前缀?只配 ProxyFix 够不够?这篇用同一个请求对比各参数,再用真实的 nginx 子路径验证(HTTPS 与 X-Forwarded-For 见第 134、135 篇)。

10.0.0.1 → 203.0.113.5
x_for 从 1 改成 2 时 remote_addr 的变化(链 203.0.113.5, 10.0.0.1)
/app/items/
同时配好 nginx 与 ProxyFix 后 url_for 生成的地址
X-Forwarded-Prefix
子路径部署时 nginx 必须传的头,缺它 ProxyFix 的 x_prefix 无效

各参数改了什么(含 x_prefix)

实测 · 本机执行输出
  [没有 ProxyFix]
     remote_addr=127.0.0.1 scheme=http host=internal:8000 script_root=''
     url_for("items")=/items/ | 静态文件=/static/a.css | _external=http://internal:8000/items/
  [x_for=1, x_proto=1]
     remote_addr=10.0.0.1 scheme=https host=internal:8000 script_root=''
     url_for("items")=/items/ | 静态文件=/static/a.css | _external=https://internal:8000/items/
  [x_for=1, x_proto=1, x_host=1]
     remote_addr=10.0.0.1 scheme=https host=shop.example.test script_root=''
     url_for("items")=/items/ | 静态文件=/static/a.css | _external=https://shop.example.test/items/
  [x_for=2]
     remote_addr=203.0.113.5 scheme=https host=internal:8000 script_root=''
     url_for("items")=/items/ | 静态文件=/static/a.css | _external=https://internal:8000/items/
  [全部 =1(x_for/proto/host/port/prefix)]
     remote_addr=10.0.0.1 scheme=https host=shop.example.test:8443 script_root='/app'
     url_for("items")=/app/items/ | 静态文件=/app/static/a.css | _external=https://shop.example.test:8443/app/items/

上一篇:Nginx 反向代理;下一篇:静态文件生产部署。

nginx 子路径部署

实测 · 本机执行输出
  [没有 ProxyFix]
     浏览器访问 /app/items/ → url_for = /items/ | 静态 = /static/a.css | 表单 action = /items/ | 重定向 Location = /items/
  [ProxyFix(x_prefix=1),但 nginx 没传 X-Forwarded-Prefix]
     浏览器访问 /app/items/ → url_for = /items/ | 静态 = /static/a.css | 表单 action = /items/ | 重定向 Location = /items/
  [ProxyFix(x_prefix=1) + nginx 传 X-Forwarded-Prefix: /app]
     浏览器访问 /app/items/ → url_for = /app/items/ | 静态 = /app/static/a.css | 表单 action = /app/items/ | 重定向 Location = /app/items/

nginx 是自己起的实例(非默认端口),gunicorn 用 --forwarded-allow-ips 设成不信任回环,让 ProxyFix 来负责。

分步演示

ProxyFix 的作用
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / Python 3.14.7 / Flask 3.1.3 / Werkzeug 3.1.9 / Jinja2 3.1.6 / SQLAlchemy 2.1.1 / gunicorn 26.2.0(都装在自己的虚拟环境里);大多数实验用 Flask 的 test_client(直接调用 WSGI 应用,不经过网络),需要真实 HTTP 时另起 gunicorn 或开发服务器(端口 9600 以上,本机 127.0.0.1);计时用 time.perf_counter,数字每次运行会有小幅抖动。Werkzeug 3.1.9 ProxyFix、nginx 1.31.6
    • 没有验证:APPLICATION_ROOT 配置与 ProxyFix 的 x_prefix 的差别、蓝图 url_prefix 与代理前缀叠加、x_port 在非标准端口下的细节、Forwarded 标准头(RFC 7239)
    京ICP备2026067502号-1京公网安备11010502063487号