模板里出错时 Flask 给用户和开发者各看到什么?行号对不对?流式模板出错时客户端会收到什么?这篇逐种错误触发一遍,并用真实的 gunicorn 看流式模板出错的下场。
GET /undef → UndefinedError: 'user' is undefined | traceback 里的模板帧: ['undef.html:2'] GET /syntax → TemplateSyntaxError: Expected an expression, got 'end of statement block' | traceback 里的模板帧: ['syntax.html:4'] GET /missing-tpl → TemplateNotFound: nope.html | traceback 里的模板帧: [] GET /typeerr → TypeError: unsupported operand type(s) for +: 'NoneType' and 'int' | traceback 里的模板帧: ['typeerr.html:2'] GET /in-include → ZeroDivisionError: division by zero | traceback 里的模板帧: ['outer.html:2', 'inner.html:2'] (模板帧 = Jinja 把渲染异常的 traceback 改写成指向模板文件与行号;语法错误时异常对象自带 filename 与 lineno) TemplateSyntaxError 的属性:lineno = 4 | name = syntax.html | filename 末尾 = syntax.html | message = Expected an expression, got 'end of statement block'
上一篇:模板中的惰性对象;下一篇:模板缓存。流式响应的更多细节见Streaming Response。
GET /undef → 500 '自定义 500 页' GET /missing-tpl → 500 '自定义 500 页' GET /in-include → 500 '自定义 500 页'
默认 Undefined 渲染 [{{ nothing }}] → '[]'
jinja_env.undefined = StrictUndefined 后 → UndefinedError: 'nothing' is undefinedGET /render-bad → HTTP/1.1 500 INTERNAL SERVER ERROR | curl 退出码 0 | 收到的正文 '自定义 500 页' GET /stream-bad → HTTP/1.1 200 OK | curl 退出码 18 | 收到的正文 '<ul>\n<li>1</li>\n<li>2</li>\n<li>3</li>\n<li>4' 服务器日志里的错误行: ['[2026-10-02 11:42:34,175] ERROR in app: Exception on /render-bad [GET]', 'ZeroDivisionError: division by zero', '[2026-10-02 11:42:34 +0800] [53378] [ERROR] Error handling request'] curl 退出码 18 表示「传输提前结束」(chunked 响应没有正常收尾)。/stream-bad 已经发出的 <ul>、<li>1 等内容留在了客户端,状态码仍是 200,因为状态行在渲染之前就发出去了。
debug 页面:状态 500;含模板文件名 undef.html: True;含出错的模板源码行 {{ user.name.first }}: True;含 UndefinedError: True