现在位置: 首页 > Flask 教程 > 正文

Flask 错误处理

Flask 提供了灵活的错误处理机制,可以捕获并处理应用中的各种错误。

优秀的错误处理不只是「不出 Bug」,更是当 Bug 发生时,给用户一个友好的体验。

本章介绍 Flask 中如何自定义错误页面和管理日志。


自定义错误页面

默认情况下,Flask 对 404 等错误会显示简单的黑底白字页面。

使用 @app.errorhandler 装饰器可以为特定 HTTP 状态码定制错误页面:

实例

from flask import Flask, render_template

app = Flask(__name__)

# 处理 404 错误——页面未找到
@app.errorhandler(404)
def page_not_found(error):
    # 注意:必须显式返回状态码 404
    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

对应的 404 模板:

实例

<!-- 文件路径: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 状态码,浏览器和搜索引擎不会认为这是一个错误页面。


异常类注册

除了状态码,@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

使用 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
        # description 参数会被传递给 errorhandler
        abort(404, description=f"文章 ID {article_id} 不存在")

    return f"<h1>{article['title']}</h1>"

@app.get("/admin")
def admin_panel():
    # 没有 admin 权限的用户访问管理后台
    abort(403, description="你没有管理员权限")

日志记录

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。生产环境中应按需设置为 INFOWARNING,避免输出太多无用信息。


配置日志输出

将日志写入文件,便于事后分析和排查:

实例

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)

捕获未处理的异常

使用 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>如果持续出现此问题,请联系 RUNOOB 技术支持。</p>
    """
, 500

常见 HTTP 错误码速查

状态码 含义 常见原因
400 Bad Request 请求参数格式错误、缺少必要字段
401 Unauthorized 用户未登录或认证失败
403 Forbidden 用户已登录但没有访问权限
404 Not Found 资源(文章、用户等)不存在
405 Method Not Allowed 使用了错误的 HTTP 方法(如用 GET 访问 POST 接口)
500 Internal Server Error 代码异常、数据库连接失败等未处理的错误