自定义出错页面

Flask 有一个方便的 abort() 函数,它可以通过一个 HTTP 出错代码退出一个请求。它还提供一个包含基本说明的出错页面,页面显示黑白的文本,很朴素。

用户可以根据错误代码或多或少知道发生了什么错误。

常见出错代码

以下出错代码是用户常见的,即使应用正常也会出现这些出错代码:

  • 404 Not Found
  • 这是一个古老的“朋友,你使用了一个错误的 URL ”信息。这个信息出现得如此频繁,以至于连刚上网的新手都知道 404 代表:该死的,我要看的东西不见了。一个好的做法是确保 404 页面上有一些真正有用的东西,至少要有一个返回首页的链接。

  • 403 Forbidden

  • 如果你的网站上有某种权限控制,那么当用户访问未获授权内容时应当发送403 代码。因此请确保当用户尝试访问未获授权内容时得到正确的反馈。

  • 410 Gone

  • 你知道 “404 Not Found” 有一个名叫 “410 Gone” 的兄弟吗?很少有人使用这个代码。如果资源以前曾经存在过,但是现在已经被删除了,那么就应该使用410 代码,而不是 404 。如果你不是在数据库中把文档永久地删除,而只是给文档打了一个删除标记,那么请为用户考虑,应当使用 410 代码,并显示信息告知用户要找的东西已经删除。

  • 500 Internal Server Error

  • 这个代码通常表示程序出错或服务器过载。强烈建议把这个页面弄得友好一点,因为你的应用 迟早 会出现故障的(参见 应用错误处理 )。

出错处理器

一个出错处理器是一个返回响应的函数,就像一个视图函数类似。不同之处在于出错处理器在某类错误引发时作出响应,而视图在发生 URL 匹配的请求时作出响应。出错处理器传递错误错误实例,大多数情况是一个HTTPException 。但是处理“ 500 Internal Server Error ”的处理器除了 500 错误外还会传递未捕获的异常。

出错处理器使用 errorhandler() 装饰器或者register_error_handler() 方法注册。出错处理器可以为一个状态码(如 404 )注册,也可以为一个异常类注册。

响应的代码不会被设置为处理器的代码。因此请确保在从处理器返回响应时,提供恰当的 HTTP 状态代码。

“500 Internal Server Error” 的出错处理器在调试模式下不会启用,而会显示交互调试器。

以下是一个处理 “404 Page Not Found” 异常的示例:

  1. from flask import render_template
  2. @app.errorhandler(404)
  3. def page_not_found(e):
  4. # note that we set the 404 status explicitly
  5. return render_template('404.html'), 404

使用 工厂模式 的话:

  1. from flask import Flask, render_template
  2. def page_not_found(e):
  3. return render_template('404.html'), 404
  4. def create_app(config_filename):
  5. app = Flask(__name__)
  6. app.register_error_handler(404, page_not_found)
  7. return app

示例模板:

  1. {% extends "layout.html" %}
  2. {% block title %}Page Not Found{% endblock %}
  3. {% block body %}
  4. <h1>Page Not Found</h1>
  5. <p>What you were looking for is just not there.
  6. <p><a href="{{ url_for('index') }}">go somewhere nice</a>
  7. {% endblock %}

以 JSON 格式返回 API 错误

当把 Flask 用于 网络 API 的时候,可以使用上述同样的技术,以 JSON 格式返回错误。调用 abort() 时使用 description 参数,errorhandler() 会把它作为 JSON 格式的错误信息,并设置状态码为404 。

  1. from flask import abort, jsonify
  2. @app.errorhandler(404)
  3. def resource_not_found(e):
  4. return jsonify(error=str(e)), 404
  5. @app.route("/cheese")
  6. def get_one_cheese():
  7. resource = get_resource()
  8. if resource is None:
  9. abort(404, description="Resource not found")
  10. return jsonify(resource)