@Errorhandler未生效主因是注册时机或作用域错误:需在app.run()前注册,工厂函数中须显式调用注册函数;蓝本中定义需调用register_blueprint;before_request等钩子异常默认不被捕获。

flask @errorhandler 为什么没生效?常见拦截失效原因
根本原因往往不是装饰器写错了,而是注册时机或作用域不对。Flask 的 @errorhandler 只对当前 Flask 实例(或蓝本)内抛出的异常有效,且必须在应用实例创建后、app.run() 前完成注册。
- 在工厂函数里定义了
@errorhandler,但忘了在create_app()中调用它 —— 装饰器只是“标记”,不执行就等于没注册 - 把
@errorhandler写在蓝本(Blueprint)里,却没调用app.register_blueprint(bp)—— 蓝本里的错误处理器不会自动挂载到 app 上 - 异常发生在
before_request或teardown_request钩子中 —— 这些钩子里抛出的异常,@errorhandler默认捕获不到(除非是 500 级别) - 用了异步视图(
async def)但 Flask 版本 @errorhandler 无响应
捕获 404、500 和自定义异常的写法差异
不同状态码/异常类型,注册方式和行为略有区别:404 和 500 是 http 状态码,可直接用数字;而自定义异常必须是类,且需继承 Exception(否则 Flask 不认)。
-
@app.errorhandler(404):捕获所有未匹配路由的请求,返回值必须是响应对象或字符串(Flask 自动包装为 404 响应) -
@app.errorhandler(500):仅捕获视图函数内未处理的异常,不包括启动失败、WSGI 层错误等 -
@app.errorhandler(MyCustomError):要求MyCustomError是真实定义的类,不能是字符串名;抛出时必须用raise MyCustomError("msg") - 注意:
@errorhandler函数的参数不是Exception实例,而是具体异常对象(如e),可从中取e.args、str(e)或自定义属性
@app.errorhandler(404) def not_found(e): return {"error": "resource not found"}, 404 class ValidationError(Exception): pass @app.errorhandler(ValidationError) def handle_validation(e): return {"error": str(e)}, 400
全局错误处理器 vs 蓝本局部处理器:优先级和覆盖规则
蓝本注册的 @errorhandler 仅对蓝本内路由生效;若蓝本内没定义,才会退回到 app 级别。但一旦蓝本定义了某个码(比如 404),它就完全屏蔽 app 级同码处理器 —— 没有“合并”或“委托”机制。
- 多个蓝本都注册了
@errorhandler(500),只有最后一个注册的生效(按register_blueprint顺序) - 想让某蓝本沿用 app 级 500 处理,就别在该蓝本里注册
@errorhandler(500) - 蓝本里注册
@errorhandler时,装饰器必须写在蓝本对象上(@bp.errorhandler(400)),不是@app.errorhandler - 蓝本级处理器返回的响应,其
Content-Type默认是text/html,除非显式指定jsonify或设置mimetype
生产环境必须加的兜底:日志记录和敏感信息过滤
开发时打印 traceback 很方便,但上线后直接暴露堆栈是严重安全隐患。Flask 的 @errorhandler 不自动记录日志,必须手动加 app.logger.error(),且不能把原始异常详情返回给前端。
立即学习“Python免费学习笔记(深入)”;
- 避免在响应体里返回
str(e)或repr(e)—— 可能泄露路径、变量名、数据库结构 - 用
traceback.format_exc()记录完整堆栈到日志,但响应只返回泛化提示(如 “server error”) - 区分调试模式:
app.debug为True时才返回详细错误页(Flask 自带),否则一律走@errorhandler(500) - 注意:
500处理器本身再抛异常,会导致 Flask 返回默认白屏错误(Werkzeug 的 Development Server 页面),无法二次捕获
最易被忽略的一点:错误处理器函数内部不能依赖请求上下文以外的状态(比如未初始化的扩展实例),否则可能在处理错误时又触发新错误,形成死循环。