当前已完成功能中,用户资料修改存在一个bug,若本地存在两个用户admin和admin1,将admin的用户名修改为admin1,就会出现报错信息。对于此类服务器错误不应该简单粗暴的进行展示,而应该设置特定的页面进行错误的提示。
在非debug模式下,页面不会展示具体的错误信息。
在debug模式下,可以展示具体的错误信息。
使用@errorhandler
装饰器,来声明自定义错误处理程序。
修改app/__init__.py
脚本,编写并注册自定义处理函数。
def create_app():
......handler(404)def not_found_error(error):return render_template('error/404.html'), 404handler(500)def internal_error(error):return render_template('error/500.html'), 500return application
新建app/templates/error/404.html
模板文件,增加404错误提示。
{% extends 'base.html' %}{% block content %}<h1>网页未找到</h1><p><a href="{{ url_for('index') }}">返回首页</a></p>
{% endblock %}
新建app/templates/error/500.html
模板文件,增加500错误提示。
{% extends 'base.html' %}{% block content %}<h1>发生意外错误</h1><p>已通知管理员,给您带来的不便,请多多原谅</p><p><a href="{{ url_for('index') }}">返回首页</a></p>
{% endblock %}
将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'))
......
修改后,重启服务测试结果。
修改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']
新增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']),# 邮件发送地址fromaddrfig['MAIL_USERNAME'],# 邮件接收地址toaddrsfig['MAIL_ADMINS'],# 邮件标题subject='flask-mega-tutorial博客异常',# 邮箱验证信息credentials=auth,# 是否启用加密secure=secure)mail_handler.setLevel(logging.ERROR)app.logger.addHandler(mail_handler)
修改app/__init__.py
脚本,新增邮件实例初始化处理。
def create_app():
......# 非DEBUG模式下,异常日志通过电子邮件发送if not application.debug:from app.logger import init_emailinit_email(application)
......return application
修改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('微博已启动')
修改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
修改pycharm中启动服务时的环境变量。
修改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('请使用其他用户名')
修改app/user.py
脚本,初始化表单时传入当前用户名。
class UserInfoEditView(View):"""用户资料编辑"""methods = ['GET', 'POST']decorators = [login_required]def dispatch_request(self):form = UserInfoEditForm(current_user.username)
......
本文发布于:2024-02-05 04:47:23,感谢您对本站的认可!
本文链接:https://www.4u4v.net/it/170724471463161.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
留言与评论(共有 0 条评论) |