1. 自定义错误页面
默认情况下,Flask对404等错误会显示简单的黑底白字页面。使用@app.errorhandler装饰器可以为特定HTTP状态码定制错误页面:
from flask import Flask, render_template app = Flask(__name__) # 处理404错误——页面未找到 @app.errorhandler(404) def page_not_found(error): return render_template("404.html"), 404 # 处理500错误——服务器内部错误 @app.errorhandler(500) def internal_error(error): return render_template("500.html"), 500 # 处理403错误——禁止访问 @app.errorhandler(403) def forbidden(error): return render_template("403.html"), 403
templates/404.html:
<!DOCTYPE html> <html> <head> <title>404 - 页面不存在</title> <style> body { text-align: center; padding-top: 60px; font-family: Arial; } h1 { font-size: 72px; color: #e74c3c; margin: 0; } p { color: #666; font-size: 18px; } a { color: #3498db; } </style> </head> <body> <h1>404</h1> <p>抱歉,你访问的页面不存在。</p> <p><a href="/">返回首页</a></p> </body> </html>
⚠️ 重要 :在
errorhandler装饰的函数中,return必须显式带上状态码 。如果不写, 404,Flask会默认返回200状态码,浏览器和搜索引擎不会认为这是一个错误页面。
2. 异常类注册
除了状态码,@app.errorhandler还可以直接注册异常类:
from werkzeug.exceptions import HTTPException @app.errorhandler(HTTPException) def handle_http_exception(error): """统一处理所有HTTP异常(如400, 401, 403, 404等)""" return f""" <h1>HTTP 错误 {error.code}</h1> <p>{error.description}</p> <p><a href="/">返回 RUNOOB 首页</a></p> """, error.code # 也可以注册自定义异常类 class CustomError(Exception): pass @app.errorhandler(CustomError) def handle_custom_error(error): return "自定义错误发生了", 400
3. 使用abort触发错误
在视图函数中,使用abort()主动触发HTTP错误:
from flask import abort # 模拟文章数据库 articles = { 1: {"title": "Flask 入门教程"}, 2: {"title": "Python 基础"}, } @app.get("/article/<int:article_id>") def view_article(article_id): article = articles.get(article_id) if article is None: # 文章不存在,返回404 abort(404, description=f"文章 ID {article_id} 不存在") return f"<h1>{article['title']}</h1>" @app.get("/admin") def admin_panel(): # 没有权限访问管理后台 abort(403, description="你没有管理员权限")
abort()的description参数会被传递给errorhandler,可以在自定义错误页面中显示详细信息。
4. 日志记录
Flask使用Python标准库的logging模块,通过app.logger即可记录日志。日志对于排查问题至关重要------不要只用print(),日志提供了更丰富的上下文和更好的控制力。
from flask import Flask, request app = Flask(__name__) @app.route("/") def index(): # 不同级别的日志 app.logger.debug("访问首页") app.logger.info("用户来自 IP: %s", request.remote_addr) app.logger.warning("检测到异常访问模式") app.logger.error("数据库连接失败") app.logger.critical("磁盘空间不足,服务即将中止") return "OK"
日志级别(由低到高)
| 级别 | 使用场景 |
|---|---|
DEBUG |
开发调试时的详细信息,生产环境默认不输出 |
INFO |
一般的运行信息,如请求记录、服务启动 |
WARNING |
警告信息,潜在问题但不影响当前运行 |
ERROR |
错误信息,某个功能出错但服务还在运行 |
CRITICAL |
严重错误,可能导致服务停止 |
在Debug模式下,Flask的日志级别自动设为
DEBUG。生产环境中应按需设置为INFO或WARNING,避免输出太多无用信息。
5. 配置日志输出到文件
将日志写入文件,便于事后分析和排查:
import logging from logging.handlers import RotatingFileHandler # 配置文件日志处理器——日志文件达到10MB后自动轮转 handler = RotatingFileHandler( "runoob_app.log", maxBytes=10 * 1024 * 1024, # 单个文件最大10MB backupCount=5 # 保留最近5个备份 ) # 设置日志格式 handler.setFormatter(logging.Formatter( "[%(asctime)s] %(levelname)s in %(module)s: %(message)s" )) # 将handler添加到Flask的logger app.logger.addHandler(handler) app.logger.setLevel(logging.INFO)
日志格式常用占位符
| 占位符 | 说明 |
|---|---|
%(asctime)s |
时间戳 |
%(levelname)s |
日志级别(INFO、ERROR等) |
%(module)s |
模块名 |
%(funcName)s |
函数名 |
%(lineno)d |
行号 |
%(message)s |
日志消息 |
6. 捕获未处理的异常
使用@app.errorhandler(500)可以捕获未处理的异常并记录日志:
import traceback @app.errorhandler(500) def internal_error(error): # 记录完整的异常堆栈 app.logger.error("服务器内部错误:\n%s", traceback.format_exc()) # 向用户显示友好的错误页面 return """ <h1>500 - 服务器内部错误</h1> <p>抱歉,服务器遇到了一个意外错误。我们已记录该问题,请稍后再试。</p> <p>如果持续出现此问题,请联系技术支持。</p> """, 500
7. 蓝图中的错误处理
蓝图也支持独立的错误处理器,只作用于该蓝图的路由:
# auth.py from flask import Blueprint, render_template bp = Blueprint("auth", __name__) @bp.errorhandler(404) def auth_not_found(error): """auth蓝图专用的404错误页面""" return render_template("auth/404.html"), 404
| 注册方式 | 作用范围 |
|---|---|
@app.errorhandler |
全局生效 |
@bp.errorhandler |
仅在该蓝图路由中生效 |
8. 常见HTTP错误码速查
| 状态码 | 含义 | 常见原因 |
|---|---|---|
| 400 | Bad Request | 请求参数格式错误、缺少必要字段 |
| 401 | Unauthorized | 用户未登录或认证失败 |
| 403 | Forbidden | 用户已登录但没有访问权限 |
| 404 | Not Found | 资源(文章、用户等)不存在 |
| 405 | Method Not Allowed | 使用了错误的HTTP方法 |
| 429 | Too Many Requests | 请求频率超过限制 |
| 500 | Internal Server Error | 代码异常、数据库连接失败等未处理错误 |
| 502 | Bad Gateway | 代理服务器收到无效响应 |
| 503 | Service Unavailable | 服务暂时不可用 |
9. 错误处理最佳实践
| 实践 | 说明 |
|---|---|
| ✅ 自定义错误页面 | 使用@app.errorhandler覆盖默认错误页面,保持品牌一致性 |
| ✅ 记录错误日志 | 在errorhandler中记录traceback,便于排查问题 |
| ✅ 区分客户端错误(4xx)和服务器错误(5xx) | 前者返回提示信息,后者记录完整堆栈 |
| ✅ 使用环境变量控制日志级别 | 开发环境用DEBUG,生产环境用INFO或WARNING |
| ✅ 敏感信息脱敏 | 错误日志中不要记录密码、Token等敏感信息 |
| ❌ 在生产环境暴露堆栈 | 不要向用户显示完整的异常堆栈 |
| ❌ 忽略错误 | 每个abort()和可能抛异常的地方都应有对应的处理 |
小结
本章全面讲解了Flask的错误处理与日志机制。@app.errorhandler装饰器可自定义各类HTTP错误页面,支持状态码和异常类两种注册方式;视图函数中使用abort()主动触发错误并传递描述信息;日志通过app.logger记录,支持DEBUG到CRITICAL五个级别,可配合RotatingFileHandler实现日志文件的自动轮转;traceback.format_exc()可捕获异常堆栈;蓝图也支持独立的错误处理器。完善的错误处理加上规范的日志记录,是打造健壮可靠Web应用的必备手段。