Ответ сервера
Flask предлагает три варианта для создания ответа:
- В виде строки или с помощью шаблонизатора
- Объекта ответа
- Кортежа в формате (
response, status, headers
) или (response, headers
)
Далее о каждом поподробнее.
Создание ответа в виде строки
@app.route('/books/<genre>')
def books(genre):
return "All Books in {} category".format(genre)
До сих пор этот способ использовался, чтобы отправлять ответ клиенту. Когда Flask видит, что из функции представления возвращается строка, он автоматически конвертирует ее в объект ответа (с помощью метода make_response()
) со строкой, содержащей тело ответа, статус-код HTTP 200 и значение text/html
в заголовке content-type
. В большинстве случаев это — все, что нужно. Но иногда необходимы дополнительные заголовки перед отправлением ответа клиенту. Для этого создавать ответ нужно с помощью функции make_response()
.
Создание ответа с помощью make_response()
Синтаксис make_response()
следующий:
res_obj = make_response(res_body, status_code=200)
res_body
— обязательный аргумент, представляющий собой тело ответа, а status_code
— опциональный, по умолчанию его значение равно 200.
Следующий код показывает, как добавить дополнительные заголовки с помощью функции make_response()
.
from flask import Flask, make_response,
@app.route('/books/<genre>')
def books(genre):
res = make_response("All Books in {} category".format(genre))
res.headers['Content-Type'] = 'text/plain'
res.headers['Server'] = 'Foobar'
return res
Следующий — демонстрирует, как вернуть ошибку 404 с помощью make_response()
.
@app.route('/')
def http_404_handler():
return make_response("<h2>404 Error</h2>", 400)
Настройка куки — еще одна базовая задача для любого веб-приложения. Функция make_response()
максимально ее упрощает. Следующий код устанавливает два куки в клиентском браузере.
@app.route('/set-cookie')
def set_cookie():
res = make_response("Cookie setter")
res.set_cookie("favorite-color", "skyblue")
res.set_cookie("favorite-font", "sans-serif")
return res
Примечание: куки обсуждаются подробно в уроке «Куки во Flask».
Куки, заданные в вышеуказанном коде, будут активны до конца сессии в браузере. Можно указать собственную дату истечения их срока, передав в качестве третьего аргумента в методе set_cookie()
количество секунд. Например:
@app.route('/set-cookie')
def set_cookie():
res = make_response("Cookie setter")
res.set_cookie("favorite-color", "skyblue", 60*60*24*15)
res.set_cookie("favorite-font", "sans-serif", 60*60*24*15)
return res
Здесь, у куки будут храниться 15 дней.
Создание ответов с помощью кортежей
Последний способ создать ответ — использовать кортежи в одном из следующих форматов:
(response, status, headers)
(response, headers)
(response, status)
response
— строка, представляющая собой тело ответа, status
— код состояния HTTP, который может быть указан в виде целого числа или строки, а headers
— словарь со значениями заголовков.
@app.route('/')
def http_500_handler():
return ("<h2>500 Error</h2>", 500)
Функция представления вернет ошибку HTTP 500 Internal Server Error. Поскольку при создании кортежей можно не писать скобки, вышеуказанный код можно переписать следующим образом:
@app.route('/')
def http_500_handler():
return "<h2>500 Error</h2>", 500
Следующий код демонстрирует, как указать заголовки с помощью кортежей:
@app.route('/')
def render_markdown():
return "## Heading", 200, {'Content-Type': 'text/markdown'}
Сможете догадаться, что делает следующая функция?
@app.route('/transfer')
def transfer():
return "", 302, {'location': 'https://localhost:5000/login'}
Функция представления перенаправляет пользователя на https://localhost:5000/login
с помощью ответа 302 (временное перенаправление). Перенаправление пользователей — настолько распространенная практика, что во Flask для этого есть даже отдельная функция redirect()
.
from flask import Flask, redirect
@app.route('/transfer')
def transfer():
return redirect("https://localhost:5000/login")
По умолчанию, redirect()
осуществляет 302 редиректы. Чтобы использовать 301, нужно указать это в функции redirect()
:
from flask import Flask, redirect
@app.route('/transfer')
def transfer():
return redirect("https://localhost:5000/login", code=301)
Перехват запросов
В веб-приложениях часто нужно исполнить определенный код до или после запроса. Например, нужно вывести весь список IP-адресов пользователей, которые используют приложение или авторизовать пользователя до того как показывать ему скрытые страницы. Вместе того чтобы копировать один и тот же код внутри каждой функции представления, Flask предлагает следующие декораторы:
before_first_request
: этот декоратор выполняет функцию еще до обработки первого запросаbefore_request
: выполняет функцию до обработки запросаafter_request
: выполняет функцию после обработки запроса. Такая функция не будет вызвана при возникновении исключений в обработчике запросов. Она должна принять объект ответа и вернуть тот же или новый ответ.teardown_request
: этот декоратор похож наafter_request
. Но вызванная функция всегда будет выполняться вне зависимости от того, возвращает ли обработчик исключение или нет.
Стоит отметить, что если функция в before_request
возвращает ответ, тогда обработчик запросов не вызывается.
Следующий код демонстрирует, как использовать эти точки перехвата во Flask. Нужно создать новый файл hooks.py
с таким кодом:
from flask import Flask, request, g
app = Flask(__name__)
@app.before_first_request
def before_first_request():
print("before_first_request() called")
@app.before_request
def before_request():
print("before_request() called")
@app.after_request
def after_request(response):
print("after_request() called")
return response
@app.route("/")
def index():
print("index() called")
return '<p>Testings Request Hooks</p>'
if __name__ == "__main__":
app.run(debug=True)
После этого необходимо запустить сервер и сделать первый запрос, перейдя на страницу https://localhost:5000/
. В консоли, где был запущен сервер, должен появиться следующий вывод:
before_first_request() called
before_request() called
index() called
after_request() called
Примечание: записи о запросах к серверу опущены для краткости.
После перезагрузки страницы отобразится следующий вывод.
before_request() called
index() called
after_request() called
Поскольку это второй запрос, функция before_first_request()
не будет вызываться.
Отмена запроса с помощью abort()
Flask предлагает функцию abort()
для отмены запроса с конкретным типом ошибки: 404, 500 и так далее. Например:
from flask import Flask, abort
@app.route('/')
def index():
abort(404)
# код после выполнения abort() не выполняется
Эта функция представления вернет стандартную страницу ошибки 404, которая выглядит вот так:
abort()
покажет похожие страницы для других типов ошибок. Если нужно изменить внешний вид страниц с ошибками, необходимо использовать декоратор errorhandler
.
Изменение страниц ошибок
Декоратор errorhandler
используется для создания пользовательских страниц с ошибками. Он принимает один аргумент — ошибку HTTP, — для которой создается страница. Откроем файл hooks.py
для создания кастомных страниц ошибок 404 и 500 с помощью декоратора:
from flask import Flask, request, g, abort
#...
#...
@app.after_request
def after_request(response):
print("after_request() called")
return response
@app.errorhandler(404)
def http_404_handler(error):
return "<p>HTTP 404 Error Encountered</p>", 404
@app.errorhandler(500)
def http_500_handler(error):
return "<p>HTTP 500 Error Encountered</p>", 500
@app.route("/")
def index():
# print("index() called")
# return '<p>Testings Request Hooks</p>'
abort(404)
if __name__ == "__main__":
#...
Стоит отметить, что оба обработчика ошибок принимают один аргумент error
, который содержит дополнительную информацию о типе ошибки.
Если сейчас посетить корневой URL, отобразится следующий ответ: