Flask学习笔记

阅读: 评论:0

Flask学习笔记

Flask学习笔记

Flask中的异常处理

文章目录

  • Flask中的异常处理
    • 1. 当前已完成功能的bug再现
      • 1.1. 将测试参数调整为非Debug模式
      • 1.2. 将测试参数调整为Debug模式
    • 2. 自定义错误页面
      • 2.1. 定义错误处理函数
      • 2.2. 新建404错误页面模板
      • 2.3. 新建500错误页面模板
      • 2.4. 启动服务测试结果
    • 3. 通过电子邮件发送错误信息
      • 3.1. 配置电子邮箱参数
      • 3.2. 编写SMTPHandler实例
      • 3.3. 初始化邮件实例
      • 3.4. 编写RotatingFileHandler日志文件记录器
      • 3.5. 初始化日志文件记录器
      • 3.6. pycharm配置环境变量测试邮件发送
    • 4. 解决该异常情况
      • 4.1. 表单增加已使用用户名校验
      • 4.2. 实例化表单时传入原用户名
      • 4.3. 启动服务测试

1. 当前已完成功能的bug再现

​ 当前已完成功能中,用户资料修改存在一个bug,若本地存在两个用户admin和admin1,将admin的用户名修改为admin1,就会出现报错信息。对于此类服务器错误不应该简单粗暴的进行展示,而应该设置特定的页面进行错误的提示。

1.1. 将测试参数调整为非Debug模式

​ 在非debug模式下,页面不会展示具体的错误信息。

1.2. 将测试参数调整为Debug模式

​ 在debug模式下,可以展示具体的错误信息。

2. 自定义错误页面

​ 使用@errorhandler装饰器,来声明自定义错误处理程序。

2.1. 定义错误处理函数

​ 修改app/__init__.py脚本,编写并注册自定义处理函数。

def create_app():
......&#handler(404)def not_found_error(error):return render_template('error/404.html'), 404&#handler(500)def internal_error(error):return render_template('error/500.html'), 500return application

2.2. 新建404错误页面模板

​ 新建app/templates/error/404.html模板文件,增加404错误提示。

{% extends 'base.html' %}{% block content %}<h1>网页未找到</h1><p><a href="{{ url_for('index') }}">返回首页</a></p>
{% endblock %}

2.3. 新建500错误页面模板

​ 新建app/templates/error/500.html模板文件,增加500错误提示。

{% extends 'base.html' %}{% block content %}<h1>发生意外错误</h1><p>已通知管理员,给您带来的不便,请多多原谅</p><p><a href="{{ url_for('index') }}">返回首页</a></p>
{% endblock %}

2.4. 启动服务测试结果

​ 将Debug模式关闭后启动服务,修改已存在的username时还是无法跳转至500错误页面,查看后台报错。

​ 报错内容如下:

Traceback (most recent call last):File "D:Projectslearnflask-mega-tutorialvenvlibsite-packageswerkzeugserving.py", line 302, in run_wsgiexecute(self.server.app)File "D:Projectslearnflask-mega-tutorialvenvlibsite-packageswerkzeugserving.py", line 290, in executeapplication_iter = app(environ, start_response)File "D:Projectslearnflask-mega-tutorialvenvlibsite-packagesflaskapp.py", line 2309, in __call__return self.wsgi_app(environ, start_response)File "D:Projectslearnflask-mega-tutorialvenvlibsite-packagesflaskapp.py", line 2295, in wsgi_appresponse = self.handle_exception(e)File "D:Projectslearnflask-mega-tutorialvenvlibsite-packagesflaskapp.py", line 1748, in handle_exceptionreturn self.finalize_request(handler(e), from_error_handler=True)File "D:Projectslearnflask-mega-tutorialapp__init__.py", line 102, in internal_errorreturn render_template('error/500.html'), 500File "D:Projectslearnflask-mega-tutorialvenvlibsite-packagesflasktemplating.py", line 135, in render_templatecontext, ctx.app)File "D:Projectslearnflask-mega-tutorialvenvlibsite-packagesflasktemplating.py", line 117, in _renderrv = der(context)File "D:Projectslearnflask-mega-tutorialvenvlibsite-packagesjinja2asyncsupport.py", line 76, in renderreturn original_render(self, *args, **kwargs)File "D:Projectslearnflask-mega-tutorialvenvlibsite-packagesjinja2environment.py", line 1008, in vironment.handle_exception(exc_info, True)File "D:Projectslearnflask-mega-tutorialvenvlibsite-packagesjinja2environment.py", line 780, in handle_exceptionreraise(exc_type, exc_value, tb)File "D:Projectslearnflask-mega-tutorialvenvlibsite-packagesjinja2_compat.py", line 37, in reraiseraise value.with_traceback(tb)File "D:Projectslearnflask-mega-tutorialapptemplateserror500.html", line 1, in top-level template code{% extends 'base.html' %}File "D:Projectslearnflask-mega-tutorialapptemplatesbase.html", line 18, in top-level template code<a href="{{ url_for('user.user_info', username=current_user.username) }}">个人资料</a>File "D:Projectslearnflask-mega-tutorialvenvlibsite-packagesjinja2environment.py", line 430, in getattrreturn getattr(obj, attribute)File "D:Projectslearnflask-mega-tutorialvenvlibsite-packagessqlalchemyormattributes.py", line 276, in __get__return (instance_state(instance), dict_)File "D:Projectslearnflask-mega-tutorialvenvlibsite-packagessqlalchemyormattributes.py", line 677, in getvalue = state._load_expired(state, passive)File "D:Projectslearnflask-mega-tutorialvenvlibsite-packagessqlalchemyormstate.py", line 660, in _load_expiredself.manager.deferred_scalar_loader(self, toload)File "D:Projectslearnflask-mega-tutorialvenvlibsite-packagessqlalchemyormloading.py", line 979, in load_scalar_attributesonly_load_props=attribute_names,File "D:Projectslearnflask-mega-tutorialvenvlibsite-packagessqlalchemyormloading.py", line 208, in load_on_identidentity_token=identity_token,File "D:Projectslearnflask-mega-tutorialvenvlibsite-packagessqlalchemyormloading.py", line 282, in load_on_pk_()File "D:Projectslearnflask-mega-tutorialvenvlibsite-packagessqlalchemyormquery.py", line 3275, in oneret = _or_none()File "D:Projectslearnflask-mega-tutorialvenvlibsite-packagessqlalchemyormquery.py", line 3244, in one_or_noneret = list(self)File "D:Projectslearnflask-mega-tutorialvenvlibsite-packagessqlalchemyormquery.py", line 3317, in __iter__return self._execute_and_instances(context)File "D:Projectslearnflask-mega-tutorialvenvlibsite-packagessqlalchemyormquery.py", line 3339, in _execute_and_instancesquerycontext, self._connection_from_session, close_with_result=TrueFile "D:Projectslearnflask-mega-tutorialvenvlibsite-packagessqlalchemyormquery.py", line 3354, in _get_bind_argsmapper=self._bind_mapper(), clause=querycontext.statement, **kwFile "D:Projectslearnflask-mega-tutorialvenvlibsite-packagessqlalchemyormquery.py", line 3332, in _connection_from_sessionconn = tion(**kw)File "D:Projectslearnflask-mega-tutorialvenvlibsite-packagessqlalchemyormsession.py", line 1123, in connectionexecution_options=execution_options,File "D:Projectslearnflask-mega-tutorialvenvlibsite-packagessqlalchemyormsession.py", line 1129, in _connection_for_bindengine, execution_optionsFile "D:Projectslearnflask-mega-tutorialvenvlibsite-packagessqlalchemyormsession.py", line 407, in _connection_for_bindself._assert_active()File "D:Projectslearnflask-mega-tutorialvenvlibsite-packagessqlalchemyormsession.py", line 294, in _assert_active% self._rollback_exception
InvalidRequestError: This Session's transaction has been rolled back due to a previous exception during flush. To begin a new transaction with this Session, first llback(). Original exception was: (sqlite3.IntegrityError) UNIQUE constraint failed: users.username
[SQL: UPDATE users SET username=?, about_me=? WHERE users.id = ?]
[parameters: ('admin1', '这是测试信息', 1)]
(Background on this error at: )

​ 通过错误提示可以看出,由于首先是username修改时,数据库提交异常但未进行session会话回滚,导致base.html页面中current_user获取失败。因此修改app/user.py脚本,增加数据库异常回滚处理。

class UserInfoEditView(View):"""用户资料编辑"""methods = ['GET', 'POST']decorators = [login_required]def dispatch_request(self):form = UserInfoEditForm()# 验证通过更新当前登录用户信息if form.validate_on_submit():current_user.username = form.username.datacurrent_user.about_me = form.about_me.data# db.sessionmit()try:db.sessionmit()except Exception as e:llback()raise eflash('您的修改已保存')return redirect(url_for('user.user_info_edit'))
......

​ 修改后,重启服务测试结果。

3. 通过电子邮件发送错误信息

3.1. 配置电子邮箱参数

​ 修改app/config.py配置文件,增加电子邮箱相关参数。其中MAIL_USERNAME为邮箱地址,MAIL_PASSWORD非邮箱登录地址,而是用于第三方邮件客户端专用的授权码。其中授权码需要自行设置。

# ----------EMAIL相关配置------------#
# 电子邮箱服务器
MAIL_SERVER = ('MAIL_SERVER')
# 电子邮箱端口,标准端口为25
MAIL_PORT = ('MAIL_PORT') or 25)
# 电子邮件服务器凭证默认不使用
MAIL_USE_TLS = ('MAIL_USE_TLS') is not None
# 电子邮箱服务器用户名
MAIL_USERNAME = ('MAIL_USERNAME')
# 电子邮箱服务器密码
MAIL_PASSWORD = ('MAIL_PASSWORD')
# 电子邮箱邮件接收地址
MAIL_ADMINS = ['your-email@example']

3.2. 编写SMTPHandler实例

​ 新增app/logger.py脚本,编写创建电子邮件实例SMTPHandler的函数。

import logging
from logging.handlers import SMTPHandlerdef init_email(app):fig['MAIL_SERVER']:auth = fig['MAIL_USERNAME'] fig['MAIL_PASSWORD']:auth = (fig['MAIL_USERNAME'], fig['MAIL_PASSWORD'])secure = fig['MAIL_USE_TLS']:secure = ()mail_handler = SMTPHandler(# 电子邮箱服务器地址mailhost=(fig['MAIL_SERVER'], fig['MAIL_PORT']),# 邮件发送地址fromaddr&#fig['MAIL_USERNAME'],# 邮件接收地址toaddrs&#fig['MAIL_ADMINS'],# 邮件标题subject='flask-mega-tutorial博客异常',# 邮箱验证信息credentials=auth,# 是否启用加密secure=secure)mail_handler.setLevel(logging.ERROR)app.logger.addHandler(mail_handler)

3.3. 初始化邮件实例

​ 修改app/__init__.py脚本,新增邮件实例初始化处理。

def create_app():
......# 非DEBUG模式下,异常日志通过电子邮件发送if not application.debug:from app.logger import init_emailinit_email(application)
......return application

3.4. 编写RotatingFileHandler日志文件记录器

​ 修改app/logger.py脚本,编写RotatingFileHandler日志文件记录器。

import os
import logging
from logging.handlers import SMTPHandler, RotatingFileHandlerdef init_logger(app):# 创建logs目录,用于存放日志文件if not ists('logs'):os.mkdir('logs')# 设置RotatingFileHandler类,最大日志文件大小为100kb,只保留10个备份文件,其会自动进行日志文件的切割和清理file_handler = RotatingFileHandler('logs/microblog.log', maxBytes=102400, backupCount=10)# logging.Formatter类为日志消息提供自定义格式# 分别记录了时间戳、日志记录级别、消息、日志来源的源代码文件和行号file_handler.setFormatter(logging.Formatter('%(asctime)s %(levelname)s: %(message)s [in %(pathname)s:%(lineno)d]'))# 设置日志类别:分别是DEBUG、INFO、WARNING、ERROR和CRITICALfile_handler.setLevel(logging.INFO)app.logger.addHandler(file_handler)# 每次服务重新启动,都会登记一条日志app.logger.setLevel(logging.INFO)app.logger.info('微博已启动')

3.5. 初始化日志文件记录器

​ 修改app/__init__.py脚本,增加RotatingFileHandler日志文件记录器注册。

def create_app():
......# 非DEBUG模式下,异常日志通过电子邮件发送if not application.debug:from app.logger import init_email, init_logger# 异常日志邮件提醒初始化init_email(application)# 日志记录器初始化init_logger(application)
......return application

3.6. pycharm配置环境变量测试邮件发送

​ 修改pycharm中启动服务时的环境变量。

4. 解决该异常情况

4.1. 表单增加已使用用户名校验

​ 修改app/forms.py脚本,增加用户名验证函数。实例化用户资料编辑表单时,增加原用户名字段,用于区分是否做出用户名修改。同时根据新的用户名判断该用户是否已被使用。

class UserInfoEditForm(FlaskForm):"""用户信息编辑表单"""username = StringField('用户名', validators=[DataRequired()])about_me = TextAreaField('个人简介', validators=[Length(min=0, max=140)])submit = SubmitField('提交')def __init__(self, original_username, *args, **kwargs):super(UserInfoEditForm, self).__init__(*args, **iginal_username = original_usernamedef validate_username(self, username):if username.data != iginal_username:user = User.query.filter_by(username=self.username.data).first()if user is not None:raise ValidationError('请使用其他用户名')

4.2. 实例化表单时传入原用户名

​ 修改app/user.py脚本,初始化表单时传入当前用户名。

class UserInfoEditView(View):"""用户资料编辑"""methods = ['GET', 'POST']decorators = [login_required]def dispatch_request(self):form = UserInfoEditForm(current_user.username)
......

4.3. 启动服务测试

本文发布于:2024-02-05 04:47:23,感谢您对本站的认可!

本文链接:https://www.4u4v.net/it/170724471463161.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:学习笔记   Flask
留言与评论(共有 0 条评论)
   
验证码:

Copyright ©2019-2022 Comsenz Inc.Powered by ©

网站地图1 网站地图2 网站地图3 网站地图4 网站地图5 网站地图6 网站地图7 网站地图8 网站地图9 网站地图10 网站地图11 网站地图12 网站地图13 网站地图14 网站地图15 网站地图16 网站地图17 网站地图18 网站地图19 网站地图20 网站地图21 网站地图22/a> 网站地图23