debug=True 到底开启了什么?它的错误页暴露了什么?调试器控制台是怎么被 PIN 保护的?模板改了为什么不用重启?这篇用真实的开发服务器一项项验证。
默认 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
页面里的 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__("os").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'
日志:
* 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