Flask 应用错误处理

应用出错,服务器出错。或早或晚,你会遇到产品出错。即使你的代码是百分百正确, 还是会时常看见出错。为什么?因为其他相关东西会出错。以下是一些在代码完全正确的 条件下服务器出错的情况:

  • 客户端已经中断了请求,但应用还在读取数据。
  • 数据库已经过载,无法处理查询。
  • 文件系统没有空间。
  • 硬盘完蛋了。
  • 后台服务过载。
  • 使用的库出现程序错误。
  • 服务器与另一个系统的网络连接出错。

以上只是你会遇到的问题的一小部分。那么如何处理这些问题呢?如果你的应用运行 在生产环境下,那么缺省情况下 Flask 会显示一个简单的出错页面,并把出错情况 记录到 logger

但可做的还不只这些,下面介绍一些更好的出错处理方法。

错误日志工具

当足够多的用户触发了错误时,发送关于出错信息的邮件,即使仅包含严重错误的邮件也会是一场灾难。更不用提从来不会去看的日志文件了。 因此,推荐使用 Sentry 来处理应用错误。它可 以在一个开源项目 on GitHub 中获得, 也可以在 hosted version 中免费试用。 Sentry 统计重复错误,捕获堆栈数据和本地变量用于排错,并在发生新的或者指定频度的错误时发送电子邮件。

  • Sentry顾名思议,翻译过来是哨兵的意思。

  • 它可以监控我们在生产环境中项目的运行状态,一旦某段代码运行报错,或者异常,会第一时间把报错的 路由异常文件请求方式 等一些非常详细的信息以消息或者邮件给我们,让我们第一时间知道:程序出错了,继而从 Sentry 给出的详细的错误信息中瞬间找到需要处理的代码,尽快把 Bug 修复。

  • Sentry是一个实时的事件日志和聚合平台。

  • Sentry 可以帮助你将程序的所有 exception 自动记录下来,处理 exception 是每个程序的必要部分,有利于我们开发。

  • 如果试用 Sentry 官方提供的服务是需要收费的,不过可以免费试用,当然最好还是自己搭建 Sentry文档 自行搭建当然就不收费啦。

  • 官网安装和使用参考

  • Docker 安装 HerePython 安装 Here

要使用 Sentry 需要安装带有 flask 依赖的 raven 客户端:

$ pip install raven[flask]
(venv) E:\Flask\myproject>pip install raven[flask]
Collecting raven[flask]
Downloading https://files.pythonhosted.org/packages/11/3a/b3e46b279b8bdd9eb55857d0e95044cad31732c80f628bb75e1e9e881a32
/raven-6.9.0-py2.py3-none-any.whl (287kB)
100% |████████████████████████████████| 296kB 4.3kB/s
Requirement already satisfied: Flask>=0.8; extra == "flask" in e:\flask\myproject\venv\lib\site-packages (from raven[fla
sk]) (1.0.2)
Collecting blinker>=1.1; extra == "flask" (from raven[flask])
Downloading https://files.pythonhosted.org/packages/1b/51/e2a9f3b757eb802f61dc1f2b09c8c99f6eb01cf06416c0671253536517b6
/blinker-1.4.tar.gz (111kB)
100% |████████████████████████████████| 112kB 8.7kB/s
Requirement already satisfied: Jinja2>=2.10 in e:\flask\myproject\venv\lib\site-packages (from Flask>=0.8; extra == "fla
sk"->raven[flask]) (2.10)
Requirement already satisfied: itsdangerous>=0.24 in e:\flask\myproject\venv\lib\site-packages (from Flask>=0.8; extra =
= "flask"->raven[flask]) (0.24)
Requirement already satisfied: click>=5.1 in e:\flask\myproject\venv\lib\site-packages (from Flask>=0.8; extra == "flask
"->raven[flask]) (6.7)
Requirement already satisfied: Werkzeug>=0.14 in e:\flask\myproject\venv\lib\site-packages (from Flask>=0.8; extra == "f
lask"->raven[flask]) (0.14.1)
Requirement already satisfied: MarkupSafe>=0.23 in e:\flask\myproject\venv\lib\site-packages (from Jinja2>=2.10->Flask>=
0.8; extra == "flask"->raven[flask]) (1.0)
Installing collected packages: blinker, raven
Running setup.py install for blinker ... done
Successfully installed blinker-1.4 raven-6.9.0

把下面内容加入 Flask 应用:

from raven.contrib.flask import Sentry
sentry = Sentry(app, dsn='YOUR_DSN_HERE')

或者,如果使用了工厂,那么可以在稍后初始化:

from raven.contrib.flask import Sentry
sentry = Sentry(dsn='YOUR_DSN_HERE') def create_app():
app = Flask(__name__)
sentry.init_app(app)
...
return app

YOUR_DSN_HERE 需要被替换为在 Sentry 安装时获得的 DSN 值。

注:关于DSN值,详情可参考Sentry自动化异常提醒一文。

简单的说就是你安装Sentry后,配置文件中 dsn 就在我们看的文档下方,每个用户的 dsn 都是唯一的,在你的项目中配置了 dsn ,Sentry 就能监控你的项目。

之后,服务信息会自动向 Sentry 报告,你就可以接收到出错通知。

错误处理

当错误发生时,你可能想要向用户显示自定义的出错页面。注册出错处理器来做到这点。

一个出错处理器是一个返回响应的普通视图函数。

但是不同之在于它不是用于路由的 ,而是用于一个异常或者当尝试处理请求时抛出 HTTP 状态码。

注册

通过使用 errorhandler() 装饰函数来注册或者稍后使用 register_error_handler() 来注册。 记得当返回响应的时候设置出错代码:

@app.errorhandler(werkzeug.exceptions.BadRequest)
def handle_bad_request(e):
return 'bad request!', 400 # or, without the decorator
app.register_error_handler(400, handle_bad_request)

当注册时, werkzeug.exceptions.HTTPException 的子类,如 BadRequest ,和它们的 HTTP 代码是可替换的。 ( BadRequest.code == 400

因为 Werkzeug 无法识别非标准 HTTP 代码,因此它们不能被注册。替代地,使用适当的代码定义一个 HTTPException 子类,注册并抛出异常类:

class InsufficientStorage(werkzeug.exceptions.HTTPException):
code = 507
description = 'Not enough storage space.' app.register_error_handler(InsuffcientStorage, handle_507) raise InsufficientStorage()

出错处理器可被用于任何异常类的注册,除了 HTTPException 子类或者 HTTP 状态码。 出错处理器可被用于特定类的注册,也可用于一个父类的所有子类的注册。

处理

在处理请求时,当 Flask 捕捉到一个异常时,它首先根据代码检索。如果该代码没 有注册处理器,它会根据类的继承来查找,确定最合适的注册处理器。如果找不到已 注册的处理器,那么 HTTPException 子类会显示 一个关于代码的通用消息。没有代码的异常会被转化为一个通用的 500 内部服务器 错误。

例如,如果一个 ConnectionRefusedError 的实例被抛出,并且一个出错处 理器注册到 ConnectionErrorConnectionRefusedError ,那么 会使用更合适的 ConnectionRefusedError 来处理异常实例,生成响应。

当一个蓝图在处理抛出异常的请求时,在蓝图中注册的出错处理器优先于在应用中全 局注册的出错处理器。但是,蓝图无法处理 404 路由错误,因为 404 发生的路由级 别还不能检测到蓝图。

日志

如何记录异常,比如向管理者发送邮件,参见 日志

排除应用错误

应用错误处理 一文所讲的是如何为生产应用设置日志和出错通知。本文要讲的是部署中配置调试的要点和如何使用全功能的 Python 调试器深挖错误。

有疑问时,请手动运行

在生产环境中,配置应用时出错?

  • 如果你可以通过 shell 来访问主机,那么首先请在部署环境中验证是否可以通过 shell 手动运行你的应用。

  • 请确保验证时使用的帐户与配置的相同,这样可以排除用户权限引发的错误。

  • 可以在你的生产服务器上, 使用 Flask 内建的开发服务器,并且设置 debug=True ,这样有助于找到配置问 题。但是,请 只在可控的情况下临时这样做 ,绝不能在生产时使用 debug=True

使用调试器

为了更深入的挖掘错误,追踪代码的执行, Flask 提供一个开箱即用的调试器(参 见 调试模式 )。如果你需要使用其他 Python 调试器,请注意调试器之 间的干扰问题。在使用你自己的调试器前要做一些参数调整:

  • debug - 是否开启调试模式并捕捉异常
  • use_debugger - 是否使用 Flask 内建的调试器
  • use_reloader - 出现异常后是否重载或者派生进程

debug 必须设置为 True (即必须捕获异常),另两个随便。

如果你正在使用 Aptana 或 Eclipse 排错,那么 use_debuggeruse_reloader 都必须设置为 False 。

一个有用的配置模式如下(当然要根据你的应用调整缩进):

FLASK:
DEBUG: True
DEBUG_WITH_APTANA: True

然后,在应用入口( main.py ),修改如下:

if __name__ == "__main__":
# To allow aptana to receive errors, set use_debugger=False
app = create_app(config="config.yaml") if app.debug: use_debugger = True
try:
# Disable Flask's debugger if external debugger is requested
use_debugger = not(app.config.get('DEBUG_WITH_APTANA'))
except:
pass
app.run(use_debugger=use_debugger, debug=app.debug,
use_reloader=use_debugger, host='0.0.0.0')

参考

我在它的基础上加入了一些命令的反馈和一些插件更具体的描述等。

Flask应用错误处理的更多相关文章

  1. Flask的错误日志处理和|ORM操作

    flask有个很人性化的处理就是 你的错误的输出是可以通过错误日志来自定义  ,让你输入的错误不再是“大黄页”, 通过 errorhandler()来装饰函数之后你的所有的输入错误的函数你都会进入这个 ...

  2. 关于flask的错误:ImportError: cannot import name 'Flask'

    刚开始接触flask,新创建后不能运行,报错如下图: 导致该错误有两种可能,没安装flask:文件名为flask. 可尝试如下两种方法解决: 方法一:若没安装过flask,则进入cmd,输入pip i ...

  3. python3.8安装flask出现错误“ModuleNotFoundError: No module named '_ctypes'”

    本想在CentOS下配置flask+nginx+uwsgi环境,结果安装最基础的flask包都出了问题...以下是我的环境: 服务器:阿里云ECS CentOS7 python版本:3.8.0 问题描 ...

  4. flask中错误使用flask.redirect('/path')导致的框架奇怪错误

    我在首页的位置使用了如下代码: import flask @page_index.route('/') def index(): flask.redirect('/pythoncgi/') 结果站点出 ...

  5. Flask进阶

    Threading.local 作用:为每个线程创建一个独立的空间,使得线程对自己的空间中的数据进行操作(数据隔离). 应用: flask上下文管理中的local中比这更高级,为协程. DBUtils ...

  6. Flask源码剖析详解

    1. 前言 本文将基于flask 0.1版本(git checkout 8605cc3)来分析flask的实现,试图理清flask中的一些概念,加深读者对flask的理解,提高对flask的认识.从而 ...

  7. Flask:初次使用Blueprints

    Windows 10家庭中文版,Python 3.6.4,Flask 1.0.2,Eclipse Oxygen.1a Release (4.7.1a),PyDev 6.3.2 本文为记录自己第一次使用 ...

  8. Flask (七) 部署

    阿里云部署Flask项目   部署Flask项目和部署Django项目基本一致,我们也使用uwsgi+nginx   我们在部署Django项目基础上部署Flask项目   1, 将uwsgi.ini ...

  9. Flask中本地栈的使用

    4种上下文变量 承接上一篇内容.当一个请求到来时,除了request被封装成全局变量之外,还有三个变量也是同样被封装成全局变量,那就是current_app.g.session.上面4个变量之所以能够 ...

随机推荐

  1. 在Hadoop集群上的HBase配置

    之前,我们已经在hadoop集群上配置了Hive,今天我们来配置下Hbase. 一.准备工作 1.ZooKeeper下载地址:http://archive.apache.org/dist/zookee ...

  2. abstract、virtual、sealed、 interface、struct 基础知识整理

    abstract abstract 修饰符指示被修改内容的实现已丢失或不完整. abstract 修饰符可用于类.方法.属性.索引和事件. 在类声明中使用 abstract修饰符以指示某个类仅旨在作为 ...

  3. SpringBoot之oauth2.0学习之服务端配置快速上手

    现在第三方登录的例子数见不鲜.其实在这种示例当中,oauth2.0是使用比较多的一种授权登录的标准.oauth2.0也是从oauth1.0升级过来的.那么关于oauth2.0相关的概念及其原理,大家可 ...

  4. 关于const用法的学习

    被const修饰的东西都受到强制保护,可以预防意外的变动,能提高程序的健壮性.所以很多C++程序设计书籍建议:“Use const whenever you need”.1.const作函数参数 例如 ...

  5. ajax与文件上传

    一.ajax ajax(Asynchronous JavaScript And XML):异步JavaScript和XML,即使用JavaScript语句与服务器进行异步交互,传输的数据为XML(也可 ...

  6. R语言实战(三)——模拟随机游走数据

    一.模拟随机游走数据示例 x <- matrix(0,1000,1) for(i in 1:1000){ x[i+1] <- x[i]+rnorm(1) } plot(x,type=&qu ...

  7. CentOS 7 安装 .Net Core 2.0 详细步骤

    轰轰烈烈的Core 热潮,从部署环境开始.参照了网上不少前辈的教程,也遇到不少的坑,这边做个完整的笔记. 一.构建.Net core 2的应用程web发布,因为是用来测试centos上的core 环境 ...

  8. Java并发编程:Java线程池核心ThreadPoolExecutor的使用和原理分析

    目录 引出线程池 Executor框架 ThreadPoolExecutor详解 构造函数 重要的变量 线程池执行流程 任务队列workQueue 任务拒绝策略 线程池的关闭 ThreadPoolEx ...

  9. JAVA对Excel的导入导出

    今天需要对比2个excel表的内容找出相同:由于要学的还很多上手很慢所以在这做个分享希望对初学的有帮助: 先是pom的配置: <dependency> <groupId>org ...

  10. 转载 一位资深程序员大牛给予Java初学者的学习路线建议

    原文链接:http://geek.csdn.net/news/detail/242336 Java学习这一部分其实也算是今天的重点,这一部分用来回答很多群里的朋友所问过的问题,那就是你是如何学习Jav ...