@app.errorhandler(404)不生效的主因是存在兜底路由(如@app.route('/'))拦截了所有未匹配请求,或注册位置错误(如误放蓝图内、调试模式下被werkzeug页面拦截);正确做法是确保其在应用实例创建后全局注册,并返回render_template('404.html'), 404。

Flask 默认不会自动触发 404 错误处理器,除非你显式调用 abort(404) 或路由完全未匹配——而后者只在没有其他路由兜底时才走全局错误处理器。
为什么自定义的 @app.errorhandler(404) 不生效?
常见原因是:你写了 @app.errorhandler(404),但同时存在一个通配路由(比如 @app.route('/<path>')</path> 或 @app.route('/<subpath>')</subpath>),它把所有未匹配请求都“吃掉”了,导致 Flask 根本没机会抛出 404 异常。
- 检查是否定义了类似
@app.route('/<subpath>')</subpath>的兜底路由,删掉或限制其匹配范围 - 确保
@app.errorhandler(404)注册在app实例上,而不是蓝图(Blueprint)里——蓝图的errorhandler只对蓝图内路由生效 - 开发模式下若启用了调试器(
debug=True),部分 404 会被 Werkzeug 调试页面拦截,关掉debug才能看到自定义页面
如何正确注册全局 404 处理器?
直接在创建 Flask 实例后注册,返回值必须是字符串或响应对象;函数名随意,但参数固定为 error(代表 NotFound 异常实例):
from flask import Flask, render_template
<p>app = Flask(<strong>name</strong>)</p><p>@app.errorhandler(404)
def not_found(error):
return render_template('404.html'), 404
</p>
注意:render_template('404.html') 必须存在,且模板中不要意外触发新异常(如访问不存在的变量),否则会 fallback 到默认 404 或 500。
使用蓝图(Blueprint)时怎么处理 404?
蓝图的 @bp.errorhandler(404) 只捕获该蓝图注册的路由下的 404,对根路径或其他蓝图无效。若需统一处理,优先用应用级 @app.errorhandler(404);若必须用蓝图,可手动在蓝图内抛出 abort(404) 触发其内部处理器:
from flask import Blueprint, abort
<p>bp = Blueprint('api', <strong>name</strong>)</p><p>@bp.route('/api/<resource>')
def get_resource(resource):
if resource not in ['users', 'posts']:
abort(404) # 这会触发 bp.errorhandler(404),而非 app 的
return {'data': resource}
</resource></p>
但要注意:这种写法会让同一个 URL 在不同上下文(蓝图 vs 应用)中可能走不同 404 处理逻辑,容易混乱。
静态文件 404 不走 @app.errorhandler(404) 怎么办?
Flask 开发服务器对 /static/xxx 这类请求有独立处理逻辑,即使文件不存在,也不会经过你的 errorhandler。解决方法只有两个:
- 在生产环境用 Nginx / Apache 代理静态文件,并配置
try_files或ErrorDocument 404指向自定义页面 - 开发时接受默认行为,或改用
send_from_directory手动控制,配合try/except捕获FileNotFoundError
别试图用通配路由覆盖 /static/——这会破坏 Flask 静态文件服务机制,引发更多问题。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











