Ответ сервера
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, а тип содержимого (content-type) назначается как text/html. Это обычно покрывает все базовые нужды.
Тем не менее, для добавления дополнительных заголовков, рациональнее применить функцию 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
Следующий пример иллюстрирует способ использования make_response()
для ответов с ошибкой 404.
@app.route('/') def http_404_handler(): return make_response("<h2>404 Error</h2>", 400)
Настройка файлов cookie является важной задачей в веб-программировании, и make_response()
позволяет сделать это легко.
Приведенный ниже пример демонстрирует установку двух cookie в браузере пользователя.
@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».
Установленные cookie будут действовать весь срок сессии браузера. Чтобы обозначить срок их действия в секундах,
используйте третий параметр метода 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
В данном примере, cookie устанавливаются сроком на 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': 'http://localhost:5000/login'}
Этот обработчик перенаправляет пользователя на URL http://localhost:5000/login
с кодом состояния
302, что означает временное перенаправление. Так как перенаправления часто есть частью работы приложения,
Flask позволяет упростить это с помощью функции redirect()
.
from flask import Flask, redirect @app.route('/transfer') def transfer(): return redirect("http://localhost:5000/login")
По умолчанию redirect()
создает 302-перенаправление. Если необходимо задать 301 статус,
укажите это в параметрах функции.
from flask import Flask, redirect @app.route('/transfer') def transfer(): return redirect("http://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>Testing Request Hooks</p>' if __name__ == "__main__": app.run(debug=True)
Запустите сервер и откройте в браузере страницу http://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>Testing Request Hooks</p>' abort(404) if __name__ == "__main__": #...
Обратите внимание, что каждый обработчик ошибок принимает аргумент error с дополнительной информацией об ошибке.
При открытии корневого URL вы увидите следующую страницу: