Skip to content

Flask - 重定向与错误处理

重定向 (Redirect) 是 Web 应用的基本组成部分。它们用于将用户的浏览器从一个 URL 发送到另一个 URL。常见用例包括:

  • 表单成功提交后重定向(例如,从登录表单重定向到用户仪表板)。
  • 操作完成后重定向(例如,删除项目后重定向回列表视图)。
  • 将用户从旧 URL 指向新 URL。
  • 强制使用规范 URL (Canonical URL)(例如,添加或移除末尾斜杠)。

Flask 提供了 redirect() 函数来生成重定向响应 (redirect response)。

from flask import redirect, url_for
# 在视图函数内部:
def process_action():
# ... 执行某些操作 ...
# 重定向到 'show_results' endpoint
return redirect(url_for('show_results'))

参数:

  • location: 要重定向用户的 URL。强烈建议使用 url_for() 生成此 URL,而不是硬编码路径。
  • code=302: 重定向的 HTTP 状态码。默认为 302 Found(临时重定向)。
  • Response=None: 可选的自定义 Response 类。

常见的重定向状态码:

  • 301 Moved Permanently(永久移动): 当资源已永久移动到新位置时使用。搜索引擎通常会更新其链接。
  • 302 Found(已找到): 默认值。表示临时重定向。客户端在将来的请求中应继续使用原始 URL。
  • 303 See Other(查看其他位置): 通常在 POST 请求后使用,通过 GET 请求将客户端重定向到不同的 URL(通常是成功页面)。有助于防止用户刷新时意外重复提交。
  • 307 Temporary Redirect(临时重定向): 类似于 302,但指示客户端对新请求使用相同的 HTTP 方法(例如,如果原始请求是 POST,则重定向请求也应是 POST)。

示例: 登录尝试后的重定向

from flask import Flask, redirect, url_for, render_template, request, flash
app = Flask(__name__)
# 消息闪现所需
app.secret_key = 'redirect-example-secret'
@app.route('/login-redir')
def login_form():
# 渲染 templates/login_redir.html
return render_template('login_redir.html')
@app.route('/process-login-redir', methods=['POST'])
def process_login():
# 模拟检查凭据
if request.form.get('username') == 'admin':
flash('Login successful!', 'success')
# 使用 url_for() 重定向到成功页
return redirect(url_for('success_page'))
else:
flash('Invalid username.', 'error')
# 登录失败,重定向回登录表单
return redirect(url_for('login_form'))
@app.route('/login-success')
def success_page():
return 'Logged in successfully!'
# 假定的模板: templates/login_redir.html
# <!DOCTYPE html><html><head><title>Login</title></head><body>
# {% with messages = get_flashed_messages(with_categories=true) %}
# {% if messages %}
# {% for category, message in messages %}<p class="{{category}}">{{ message }}</p>{% endfor %}
# {% endif %}
# {% endwith %}
# <form method="post" action="{{ url_for('process_login') }}">
# Username: <input type="text" name="username"><br>
# <input type="submit" value="Login">
# </form></body></html>
if __name__ == '__main__':
app.run(debug=True, port=5008)

有时,由于错误条件(例如,找不到资源、用户未授权、输入无效),请求 (request) 的处理无法正常继续。在这种情况下,您应该发出适当的 HTTP 错误状态信号。Flask 为此提供了 abort() 函数。

abort() 立即停止当前视图函数 (view function) 的执行,并针对给定的状态码抛出一个 HTTPException。Flask 会捕获此异常,并将相应的错误页面返回给客户端。

from flask import abort, session
@app.route('/product/<int:product_id>')
def get_product(product_id):
product = find_product_in_db(product_id) # 假设此函数存在
if product is None:
# 未找到产品,使用 404 错误终止
abort(404)
return render_template('product_details.html', product=product)
@app.route('/admin/config')
def admin_config():
if not session.get('is_admin'):
# 用户未授权,使用 403 错误终止
abort(403)
return 'Admin Configuration Page'

abort() 的常见错误状态码:

  • 400 Bad Request(错误请求):无效的请求语法或参数。
  • 401 Unauthorized(未经授权):需要认证,但缺失或失败。
  • 403 Forbidden(禁止访问):已认证用户没有权限访问该资源。
  • 404 Not Found(未找到):请求的资源无法找到。
  • 405 Method Not Allowed(方法不允许):此 URL 不支持使用的 HTTP 方法(例如 POST)。
  • 410 Gone(已失效):资源曾经存在,但已永久不可用。
  • 500 Internal Server Error(内部服务器错误):表示意料之外的服务器错误的通用代码。

您还可以向 abort() 传递 description 参数:

abort(400, description="Missing 'user_id' parameter in request.")

使用 @errorhandler 自定义错误页面

Section titled “使用 @errorhandler 自定义错误页面”

您可以使用 @errorhandler() 装饰器 (decorator) 为特定的 HTTP 错误码创建自定义的、用户友好的模板 (template),而不是显示 Flask 的默认错误页面。

from flask import render_template
@app.errorhandler(404)
def handle_not_found_error(error):
# 如果需要,记录错误日志: app.logger.warning(f'页面未找到: {request.path}')
# 'error' 参数包含有关异常的信息
return render_template('errors/404.html'), 404 # 返回模板和状态码
@app.errorhandler(403)
def handle_forbidden_error(error):
return render_template('errors/403.html'), 403
@app.errorhandler(500)
def handle_internal_error(error):
# 如果适用,在此处回滚数据库会话通常是好的做法
# db.session.rollback()
app.logger.error(f'Server Error: {error}', exc_info=True)
return render_template('errors/500.html'), 500
# --- 假定模板 ---
# templates/errors/404.html: "Sorry, the page you requested was not found."
# templates/errors/403.html: "Sorry, you do not have permission to access this page."
# templates/errors/500.html: "Sorry, something went wrong on our end. Please try again later."
# ------------------------

当发生与注册的处理程序 (handler) 对应的错误时(无论是通过 abort() 还是导致 500 错误的未处理异常 exception),Flask 将执行关联的错误处理函数,而不是其默认行为。