bigywater.tech
Flask · 29

子域名路由

想让 api.example.com 和 ann.example.com 走不同的路由,Flask 怎么配?本地怎么测?哪些坑会让子域名规则静默失效?这篇用 test client 与真实 gunicorn 都跑一遍。

2
让子域名生效必须同时具备的条件:SERVER_NAME 与 subdomain_matching=True
Host 不属于 SERVER_NAME 时被当成的子域名
0
默认配置下能匹配到子域名路由的 Host 数

默认不生效

实测 · 本机执行输出
  规则: [('/', 'www_index', ''), ('/', 'api_index', 'api'), ('/', 'user_index', '<user>')]
  Host example.test         → www 首页
  Host www.example.test     → www 首页
  Host api.example.test     → www 首页
  Host ann.example.test     → www 首页
  Host a.b.example.test     → www 首页
  Host other.test           → www 首页
  Host localhost            → www 首页

上一篇:Blueprint 的静态文件和模板目录;下一篇:URL 中的 Unicode 与编码;Host 头校验见Host Header 校验。

只设 SERVER_NAME 也不生效

实测 · 本机执行输出
  Host example.test         → www 首页
  Host www.example.test     → www 首页
  Host api.example.test     → www 首页
  Host ann.example.test     → www 首页
  Host a.b.example.test     → www 首页
  Host other.test           → www 首页
  Host localhost            → www 首页

subdomain_matching=True

实测 · 本机执行输出
  Host example.test         → www 首页
  Host www.example.test     → 用户 www 的站点
  Host api.example.test     → api 首页
  Host ann.example.test     → 用户 ann 的站点
  Host a.b.example.test     → 用户 a.b 的站点
  Host other.test           → 用户 <invalid> 的站点
  Host localhost            → 用户 <invalid> 的站点
  警告(UserWarning): ["Current server name 'localhost' doesn't match configured server name 'example.test'", "Current server name 'other.test' doesn't match configured server name 'example.test'"]

端口

实测 · 本机执行输出
  Host example.test:8000          → 主域
  Host api.example.test:8000      → api 子域
  Host api.example.test           → 404
  Host api.example.test:9999      → 404

url_for

实测 · 本机执行输出
  url_for("api_index") → http://api.example.test:5000/ | url_for("user_index", user="ann") → http://ann.example.test:5000/ | url_for("www_index") → / | _external → http://example.test:5000/

真实 HTTP

实测 · 本机执行输出
  Host: example.test:9601        → 200 www 首页
  Host: api.example.test:9601    → 200 api 首页
  Host: ann.example.test:9601    → 200 用户 ann
  Host: example.test             → 200 用户 <invalid>
  Host: evil.test:9601           → 200 用户 <invalid>

cookie 与子域名

实测 · 本机执行输出
  默认: session=eyJ4IjoxfQ.ar8hhw._ribnK42gL9L4gQ4xurNzN7TY6I; HttpOnly; Path=/
  SESSION_COOKIE_DOMAIN=".example.test": session=eyJ4IjoxfQ.ar8hhw._ribnK42gL9L4gQ4xurNzN7TY6I; Domain=example.test; HttpOnly; Path=/

分步演示

子域名路由
本步的对象

    本文用到的工具与边界

    • 本机 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,数字每次运行会有小幅抖动
    • 没有验证:host_matching=True(按完整主机名匹配)、本机 /etc/hosts 与浏览器里的真实子域名访问、通配符 DNS、反向代理改写 Host 头的情况(见第 135 篇)、Flask 其它版本里 subdomain_matching 的默认值
    京ICP备2026067502号-1京公网安备11010502063487号