Flask 的 @app.errorhandler 是最直接可控的异常处理入口,需区分错误类型、保留调试信息、避免暴露敏感数据,并注意路由顺序、蓝图作用域、静态文件404处理、兜底异常谨慎使用、API与页面响应格式动态适配、状态码与Content-Type显式设置、日志完整记录等关键细节。

Flask 的 @app.errorhandler 是最直接、最可控的异常处理入口,但「优雅」不等于只返回 HTML 页面——关键在于区分错误类型、保留调试信息、避免暴露敏感数据,同时让前端和运维能快速定位问题。
为什么 @app.errorhandler(404) 有时不生效?
常见原因是路由注册顺序或蓝图(Blueprint)作用域问题。Flask 的 errorhandler 默认只对当前应用实例生效;若使用了蓝图,需显式调用 bp.register_error_handler() 或在蓝图内定义。
- 全局 404 必须在
app实例上注册,不能只写在某个蓝图里 - 如果用了
app.register_blueprint(bp)且希望蓝图自带错误页,得在蓝图创建后立即调用bp.register_error_handler(404, handler) - 静态文件 404(如 /static/xxx.js 不存在)默认由 Flask 开发服务器捕获,不走
@app.errorhandler,生产环境应交由 Nginx 处理
@app.errorhandler(Exception) 要谨慎用
它会捕获所有未被更具体 handler 拦截的异常,包括 KeyError、ValueError 等业务逻辑错误,容易掩盖真实问题。
- 优先按 HTTP 状态码注册:如
@app.errorhandler(500)、@app.errorhandler(400) - 若必须兜底,应在 handler 内记录完整 traceback(用
logging.exception()),并返回统一 JSON 或友好提示页,绝不能直接str(e)输出到响应体 - 开发环境可返回 Werkzeug 调试页面(默认开启),但生产环境必须关闭
debug=True,否则会泄露代码路径、环境变量等
如何让 API 和页面共用一套错误处理逻辑?
靠请求头判断是否为 AJAX 请求,动态返回 JSON 或 HTML。Flask 中没有内置的「API 模式」开关,得自己识别 request.headers.get('Accept') 或自定义约定(如 URL 含 /api/)。
安全 Python 代码沙箱:在隔离的沙箱中执行任意 Python 代码,预装 requests、NumPy、pandas 库。返回 stdout、stderr。
@app.errorhandler(404)
def not_found(error):
if request.path.startswith('/api/') or 'application/json' in request.headers.get('Accept', ''):
return {'error': 'Not found'}, 404
return render_template('404.html'), 404
- 不要依赖
X-Requested-With: XMLHttpRequest,现代前端(如 fetch、axios)默认不发这个头 - 更可靠的方式是检查
request.accept_mimetypes.best_match(['application/json', 'text/html']) == 'application/json' - 若项目已分 API 蓝图和页面蓝图,直接在各自蓝图内注册对应 handler 更清晰,无需条件判断
自定义错误页面时最容易漏掉的三件事
不是模板渲染成功就完事了——HTTP 状态码、Content-Type、响应头都得手动对齐。
-
render_template('500.html')默认返回 200 状态码,必须显式写成return render_template('500.html'), 500 - 若模板含中文,确保响应头有
Content-Type: text/html; charset=utf-8(Flask 默认已设,但自定义 Response 对象时可能丢失) - 静态资源(CSS/JS)路径要用
url_for('static', filename='...'),别硬写/static/...,否则部署到子路径(如 /myapp/)时会 404
真正难的不是写几个 @app.errorhandler,而是让 500 错误发生时,日志里能立刻看到是哪个视图函数、哪行代码、什么参数触发的——这需要把 sys.exc_info() 或 traceback.format_exc() 记进日志,而不是只渲染一个「服务器出错了」的页面。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










