bigywater.tech
Flask · 15

Flask Debug Mode 与自动重载

debug=True 到底开启了什么?它的错误页暴露了什么?调试器控制台是怎么被 PIN 保护的?模板改了为什么不用重启?这篇用真实的开发服务器一项项验证。

265 → 15272
同一个 500 错误页的正文字节数(debug 关 → 开)
PIN
调试器控制台执行代码需要的认证
3 种
等价的 debug 设置方式(FLASK_DEBUG、config、app.debug)

debug 的设置方式

实测 · 本机执行输出
  默认                         app.debug = False | config[DEBUG] = False | logger 级别 = 0 | jinja auto_reload = False | TEMPLATES_AUTO_RELOAD = None
  FLASK_DEBUG=1              app.debug = True | config[DEBUG] = True | logger 级别 = 10 | jinja auto_reload = True | TEMPLATES_AUTO_RELOAD = None
  FLASK_DEBUG=0              app.debug = False | config[DEBUG] = False | logger 级别 = 0 | jinja auto_reload = False | TEMPLATES_AUTO_RELOAD = None
  app.config["DEBUG"]=True   app.debug = True | config[DEBUG] = True | logger 级别 = 10 | jinja auto_reload = True | TEMPLATES_AUTO_RELOAD = None
  app.debug = True           app.debug = True | config[DEBUG] = True | logger 级别 = 10 | jinja auto_reload = True | TEMPLATES_AUTO_RELOAD = None
  (没有设置 logger 级别时 level 为 0 = NOTSET;debug 时 Flask 在第一次访问 logger 时把级别设成 DEBUG)

上一篇:Flask 与 Werkzeug 的关系;自动重载进程的细节见app.run() 的启动过程;安全风险的专题见开发模式 Debugger 风险。

出错页的差别

实测 · 本机执行输出
  debug=False  → 500 | 正文 265 字节 | 含 Traceback: False | 含调试器标记: False | 页面里能看到源码行 return 1 / 0: False
  debug=True   → 500 | 正文 15272 字节 | 含 Traceback: True | 含调试器标记: True | 页面里能看到源码行 return 1 / 0: True

调试器控制台与 PIN

实测 · 本机执行输出
  页面里的 EVALEX = true | 页面内嵌了 SECRET: True | 页面里的栈帧数: 7
  ① 没有 PIN 认证就请求在栈帧里执行代码 → 500;返回的是应用自己的 500 页(含 "ZeroDivisionError"): True;没有执行结果: True
  ② 用错误的 PIN 认证 → 200 {"auth": false, "exhausted": false}
  ③ 用正确的 PIN(实验里用 WERKZEUG_DEBUG_PIN 环境变量固定)认证 → 200 {"auth": true, "exhausted": false};响应设置了 cookie: True(名字以 __wzdb… 开头)
  ④ 带着认证 cookie 再执行 __import__("os").getpid() → 200;返回内容里包含服务器进程的 pid: True;返回的前 80 字符:'>>> __import__(&#34;os&#34;).getpid()\n<span class="number">33139</span>'
  ⑤ 取调试器的静态资源(cmd=resource&f=style.css)→ 200,6078 字节(不需要 PIN)

模板自动重载

实测 · 本机执行输出
  非 debug  第一次读到 'version 1';改文件后读到 'version 1'
  --debug  第一次读到 'version 1';改文件后读到 'version 2'

--debug 与 --no-reload

实测 · 本机执行输出
  日志:
     * Serving Flask app 't'
     * Debug mode: on
    WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
     * Running on http://127.0.0.1:9606
    Press CTRL+C to quit

分步演示

debug 模式
本步的对象

    本文用到的工具与边界

    • 本机 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,数字每次运行会有小幅抖动。调试器实验只在本机自己起的服务器(127.0.0.1)上进行,PIN 用 WERKZEUG_DEBUG_PIN 环境变量固定为实验值
    • 没有验证:PIN 的生成算法(machine-id、MAC 地址、用户名等)与能否被推算(见第 132 篇)、Docker 容器里的 PIN、debug 页面在反向代理后的表现、exception 页面在 PROPAGATE_EXCEPTIONS 单独设置时的行为
    京ICP备2026067502号-1京公网安备11010502063487号