Flask入门教程(十五):错误处理与日志——打造健壮的Web应用

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应用的必备手段。

相关推荐
忆~遂愿4 小时前
免密连接+快捷键+虚拟鼠标:ToDesk远程操作AI效率拉满
人工智能·python·深度学习·神经网络·自然语言处理·计算机外设·安全架构
IT_Octopus4 小时前
【零基础入门 LLM 开发 · Day 11】:ChatOpenAI vs init_chat_model——一行换供应商
java·前端·javascript
ComPDFKit4 小时前
用 ComPDF DocSlight 提取 PDF 表格:三种样本实测与 Python 接入
开发语言·python·pdf·pdf表格提取
deli0074 小时前
撒下 200 个种子点,平面为什么自己长成蜂窝?Voronoi 图实验室
前端
大文说跨境4 小时前
多账号环境隔离方案技术选型:指纹浏览器、VPS 与云手机的三种架构对比
java·开发语言·前端
92year4 小时前
我用运筹学穷举了麦当劳全菜单:30 块预算,怎么吃到全局最优?
python·agent·mcp
咕白m6254 小时前
使用 C# 将 TIFF 转换为 PDF
前端·c#
用户7624117567054 小时前
第三章 流程控制语句
python
全栈项目管理程序猿4 小时前
ArcGIS JS 基础教程(28):图层渲染顺序管理
前端·javascript
huakoh4 小时前
MCP 工具报错走哪条通道:三条探针的最小复现检查
前端