404 혹은 500의 오류 페이지를 불러올 경우, 우리가 만들어둔 화면이 나오도록 설정할 수 있는 기능을 Flask에서 지원한다.
1. 사용자 정의 오류 처리기 추가
가장 일반적인 404 & 500 에러에 대한 오류 페이지를 정의해보겠다.
# vim app/errors.py
# Flask는 자체 오류 페이지를 설정할 수 있는 메커니즘을 제공한다.
from flask import render_template
from app import app, db
@app.errorhandler(404)
def not_found_error(error):
return render_template('404.html'), 404
@app.errorhandler(500)
def internal_error(error):
# 사용자 이름이 중복되는 등의 DB와 연결 중 500 에러 발생시, 정상적으로 이전 작업이 종료되지 않을 수 있어 rollback을 추가
db.session.rollback()
return render_template('500.html'), 500
2. 템플릿 만들어주기
<!-- vim app/templates/404.html -->
<!-- 템플릿 찾을 수 없음 -->
{% extends "base.html" %}
{% block content %}
<h1>File Not Found</h1>
<p><a href="{{ url_for('index') }}">Back</a></p>
{% endblock %}
<!-- vim app/templates/500.html -->
<!-- 내부 서버 오류 템플릿 -->
{% extends "base.html" %}
{% block content %}
<h1>An unexpected error has occurred</h1>
<p>The administrator has been notified. Sorry for the inconvenience!</p>
<p><a href="{{ url_for('index') }}">Back</a></p>
{% endblock %}
3. 오류 처리기를 Flask에 등록하기 위해 app에서 errors 모듈 불러오기
# vim app/__init__.py
# ...
# 오류 처리 기능 호출
from app import errors
4. 이메일 구성 설정
# vim config.py
class Config(object):
# ...
# 이메일 구성
MAIL_SERVER = os.environ.get('MAIL_SERVER')
MAIL_PORT = int(os.environ.get('MAIL_PORT') or 25)
MAIL_USE_TLS = os.environ.get('MAIL_USE_TLS') is not None
MAIL_USERNAME = os.environ.get('MAIL_USERNAME')
MAIL_PASSWORD = os.environ.get('MAIL_PASSWORD')
ADMINS = ['your-email@example.com']
5. 이메일로 오류 기록
# vim app/__init__.py
# ...
# 웹서버에서 발생하는 Log 정보를 지정해둔 메일로 발송하는 기능을 추가해, 모니터링함
import logging
from logging.handlers import SMTPHandler
if not app.debug:
if app.config['MAIL_SERVER']:
auth = None
if app.config['MAIL_USERNAME'] or app.config['MAIL_PASSWORD']:
auth = (app.config['MAIL_USERNAME'], app.config['MAIL_PASSWORD'])
secure = None
if app.config['MAIL_USE_TLS']:
secure = ()
# SMTPHandler 인스턴스 추가하여 이메일 전송 설정
mail_handler = SMTPHandler(
mailhost=(app.config['MAIL_SERVER'], app.config['MAIL_PORT']),
fromaddr='no-reply@' + app.config['MAIL_SERVER'],
toaddrs=app.config['ADMINS'], subject='Microblog Failure',
credentials=auth, secure=secure)
mail_handler.setLevel(logging.ERROR)
app.logger.addHandler(mail_handler)
6. python의 smtp 디버깅 서버로 TEST
$ python -m smtpd -n -c DebuggingServer localhost:8025
7. Gmail 계정 이메일 서버 사용하여 TEST
아래 커맨드를 서버에 직접 입력해도 되고, /etc/profile 파일에 입력해준 후 적용해주는 방법으로도 대체 가능하다.
$ source /etc/profile
export MAIL_SERVER=smtp.googlemail.com
export MAIL_PORT=587
export MAIL_USE_TLS=1
export MAIL_USERNAME=<your-gmail-username>
export MAIL_PASSWORD=<your-gmail-password>
8. 파일에 로깅하는 기능 추가
# vim app/__init__.py
# 웹서버에서 발생하는 Log 정보를 지정해둔 메일로 발송하는 기능을 추가해, 모니터링함
import logging
from logging.handlers import SMTPHandler
from logging.handlers import RotatingFileHandler
import os
if not app.debug:
# ...
# 파일에 로깅
if not os.path.exists('logs'): # logs 디렉토리 없을 경우 생성
os.mkdir('logs')
# log 파일 정보 설정 : log파일 크기 10KB 제한, 최근 10개 로그 파일을 백업으로 유지
file_handler = RotatingFileHandler('logs/microblog.log', maxBytes=10240,
backupCount=10)
# log 메시지에 대한 사용자 정의 형식 제공
file_handler.setFormatter(logging.Formatter(
'%(asctime)s %(levelname)s: %(message)s [in %(pathname)s:%(lineno)d]'))
# DEBUG, INFO, WARNING, ERROR, CRITICAL
file_handler.setLevel(logging.INFO)
app.logger.addHandler(file_handler)
app.logger.setLevel(logging.INFO)
app.logger.info('Microblog startup')
9. 프로필 편집 양식에서 사용자의 이름을 확인하는 절차 추가
# 프로필 편집기 양식
class EditProfileForm(FlaskForm):
username = StringField('Username', validators=[DataRequired()])
about_me = TextAreaField('About me', validators=[Length(min=0, max=140)])
submit = SubmitField('Submit')
# 현재 사용자 정보를 가져옴
def __init__(self, original_username, *args, **kwargs):
super(EditProfileForm, self).__init__(*args, **kwargs)
self.original_username = original_username
# 프로필 편집 양식에서 사용자의 이름을 확인
def validate_username(self, username):
if username.data != self.original_username:
user = User.query.filter_by(username=self.username.data).first()
if user is not None:
raise ValidationError('Please use a different username.')
10. 프로필 편집 양식에서 사용자의 이름을 확인하는 절차 추가
# vim app/routes.py
# ...
# 프로필 뷰 편집 기능
@app.route('/edit_profile', methods=['GET', 'POST'])
@login_required
def edit_profile():
form = EditProfileForm(current_user.username) # 프로필 편집 양식에서 사용자의 이름을 확인
# ...