Декоратор errorhandler, функции redirect и abort

Следующим важным моментом при разработке сайта является отлавливание некоторых ошибок ответа сервера. Например, при отсутствии какой-либо страницы пользователь в браузере увидит следующее:

Это есть стандартный ответ сервера с кодом 404 – страница не найдена. В таких ситуациях лучше иметь обработчик для кода 404, который бы возвращал пользователю более дружественную информацию.

Чтобы создать такой обработчик, следует использовать специальный декоратор errorhandler с указанием в нем кода ответа, с которым будет ассоциирована функция представления:

@app.errorhandler(404)
def pageNotFount(error):
    return render_template('page404.html', title="Страница не найдена", menu=menu)

Затем, добавим шаблон page404.html, например, такой:

{% extends 'base.html' %}
 
{% block content %}
{{ super() }}
Страница не найдена, вернуться на <a href="/">главную</a> страницу.
{% endblock %}

И при обновлении страницы, увидим более дружественное сообщение. Причем, код, который возвратит сервер, будет равен 200 – все хорошо.

Если все же, требуется при отображении своей собственной страницы возвращать прежний код 404, то это можно реализовать так:

return render_template('page404.html', title="Страница не найдена", menu=menu), 404

Обновляем страницу и видим в консоли, что сервер возвратил код 404. Однако, при разработке реальных сайтов, лучше в таких случаях возвращать код 200, т.е. то, что идет по умолчанию, т.к. поисковым системам «нравится», когда на сайте страницы отвечают с этим кодом и считается, что это положительно сказывается на ранжировании их в поисковой выдаче.

Перенаправление запроса

Часто при создании сайта требуется делать перенаправление пользователя на другую страницу. Например, пользователь в браузере вводит адрес страницы с формой авторизации:

http://127.0.0.1:5000/login

И, если он еще не авторизован, то отображается вот такая страница, а иначе – осуществляется переадресация на страницу профайла. Давайте для примера реализуем такой простой функционал. Обработчик представим в следующем виде:

@app.route("/login", methods=["POST", "GET"])
def login():
    if 'userLogged' in session:
        return redirect(url_for('profile', username=session['userLogged']))
    elif request.form['username'] == "selfedu" and request.form['psw'] == "123":
        session['userLogged'] = request.form['username']
        return redirect(url_for('profile', username=session['userLogged']))
 
    return render_template('login.html', title="Авторизация", menu=menu)

Мы здесь вначале с помощью сессии проверяем: авторизован ли пользователь, то есть, присутствует ли ключ 'userLogged' в сессии. И если это так, то сразу осуществляется переход на страницу профайла. Иначе идет проверка на тот случай, если пользователь уже передал данные для входа. И для username равным selfedu и пароля 123 осуществляется переход на страницу профайла. Если же обе эти проверки оказались ложными, то отображается страница с формой авторизации.

Шаблон формы авторизации можно описать так (файл login.html):

{% extends 'base.html' %}
 
{% block content %}
{{ super() }}
<form action="/login" method="post" class="form-contact">
<label>Имя: </label> <input type="text" name="username" value="" requied />
<label>Пароль: </label> <input type="password" name="psw" value="" requied />
<input type="submit" value="Войти" />
</form>
{% endblock %}

Прерывание запроса

Чтобы функционал нашего сайта довести до логического конца, на странице профайла (в обработчике profile) сделаем проверку: если пользователь самостоятельно в браузере набирает путь, например:

http://127.0.0.1:5000/profile/selfedu

то страница должна отображаться только в том случае, если пользователь авторизован. Иначе, завершить вызов ошибкой 401 – доступ запрещен. Это можно сделать так:

@app.route("/profile/<username>")
def profile(username):
    if 'userLogged' not in session or session['userLogged'] != username:
        abort(401)
 
    return f"Пользователь: {username}"

Смотрите, если в сессии нет ключа 'userLogged', то вызывается функция abort, которая указывает серверу вернуть код ошибки 401. Иначе, отображается профайл пользователя.

Таким образом, пользователь может смотреть только свой профайл и даже если попытается в запросе браузера указать логин другого человека, то получит ошибку доступа.

Видео по теме