Как обрабатывать данные входящего запроса в Flask
Введение
Веб-приложениям часто требуется обработка входящих данных запросов от пользователей. Эта полезная нагрузка может быть в форме строк запроса, данных формы и объектов JSON. Flask, как и любой другой веб-фреймворк, позволяет получить доступ к данным запроса.
В этом руководстве вы создадите приложение Flask с тремя маршрутами, которые принимают строки запроса, данные формы или объекты JSON.
Предпосылки
Для выполнения этого урока вам понадобятся:
- Для этого проекта потребуется установить Python в локальной среде.
- В этом проекте virtualenv будет использоваться в одной команде.
- Для тестирования конечных точек API потребуется загрузить и установить такой инструмент, как Postman.
Это руководство было проверено с помощью Pipenv v2020.11.15, Python v3.9.0 и Flask v1.1.2.
Настройка проекта
Чтобы продемонстрировать различные способы использования запросов, вам потребуется создать приложение Flask. Несмотря на то, что в примере приложения используется упрощенная структура для функций представления и маршрутов, то, что вы узнаете в этом руководстве, может быть применено к любому методу организации ваших представлений, например представлениям на основе классов, схемам или расширениям, таким как Flask-Via.
Во-первых, вам нужно создать каталог проекта. Откройте терминал и выполните следующую команду:
- mkdir flask_request_example
Затем перейдите в новый каталог:
- cd flask_request_example
Затем установите Flask. Откройте терминал и выполните следующую команду:
- pipenv install Flask
Команда pipenv
создаст виртуальную среду для этого проекта, Pipfile, установит flask
и Pipfile.lock.
Чтобы активировать виртуальную среду проекта, выполните следующую команду:
- pipenv shell
Чтобы получить доступ к входящим данным в Flask, вы должны использовать объект request
. Объект request
содержит все входящие данные из запроса, включая среди прочего тип mimetype, реферер, IP-адрес, необработанные данные, метод HTTP и заголовки.
Хотя вся информация, содержащаяся в объекте request
, может быть полезна, для целей этой статьи вы сосредоточитесь на данных, которые обычно напрямую предоставляются вызывающей стороной конечной точки.
Чтобы получить доступ к объекту запроса во Flask, вам нужно будет импортировать его из библиотеки Flask:
from flask import request
Затем у вас есть возможность использовать его в любой из ваших функций просмотра.
Используйте редактор кода для создания файла app.py
. Импортируйте Flask
и объект request
. А также установите маршруты для query-example
, form-example
и json-example
:
# import main Flask class and request object
from flask import Flask, request
# create the Flask app
app = Flask(__name__)
@app.route('/query-example')
def query_example():
return 'Query String Example'
@app.route('/form-example')
def form_example():
return 'Form Data Example'
@app.route('/json-example')
def json_example():
return 'JSON Object Example'
if __name__ == '__main__':
# run app in debug mode on port 5000
app.run(debug=True, port=5000)
Затем откройте терминал и запустите приложение с помощью следующей команды:
- python app.py
Приложение запустится на порту 5000, поэтому вы можете просмотреть каждый маршрут в своем браузере по следующим ссылкам:
http://127.0.0.1:5000/query-example (or localhost:5000/query-example)
http://127.0.0.1:5000/form-example (or localhost:5000/form-example)
http://127.0.0.1:5000/json-example (or localhost:5000/json-example)
Код устанавливает три маршрута, и при посещении каждого маршрута будут отображаться сообщения Пример строки запроса
, Пример данных формы
и Пример объекта JSON
соответственно.
Использование аргументов запроса
Аргументы URL-адреса, которые вы добавляете в строку запроса, — это распространенный способ передачи данных в веб-приложение. Просматривая веб-страницы, вы, вероятно, уже сталкивались со строкой запроса.
Строка запроса выглядит следующим образом:
example.com?arg1=value1&arg2=value2
Строка запроса начинается после знака вопроса (?
):
example.com?arg1=value1&arg2=value2
И имеет пары ключ-значение, разделенные символом амперсанда (&
):
example.com?arg1=value1&arg2=value2
Для каждой пары за ключом следует знак равенства (=
), а затем значение.
arg1 : value1
arg2 : value2
Строки запроса полезны для передачи данных, не требующих действий пользователя. Вы можете сгенерировать строку запроса где-нибудь в своем приложении и добавить ее к URL-адресу, чтобы, когда пользователь делает запрос, данные автоматически передавались ему. Строка запроса также может быть сгенерирована формами, у которых в качестве метода используется GET.
Давайте добавим строку запроса к маршруту query-example
. В этом гипотетическом примере вы укажете имя языка программирования, которое будет отображаться на экране. Создайте ключ language
и значение Python
:
http://127.0.0.1:5000/query-example?language=Python
Если вы запустите приложение и перейдете по этому URL-адресу, вы увидите, что оно по-прежнему отображает сообщение Пример строки запроса
.
Вам нужно будет запрограммировать часть, которая обрабатывает аргументы запроса. Этот код будет читать ключ language
с помощью request.args.get(language)
или request.args[language]
.
При вызове request.args.get(language)
приложение будет продолжать работать, если ключ language
не существует в URL-адресе. В этом случае результатом метода будет None
.
При вызове request.args[language]
приложение вернет ошибку 400, если ключ language
не существует в URL-адресе.
При работе со строками запроса рекомендуется использовать request.args.get()
, чтобы предотвратить сбой приложения.
Давайте прочитаем ключ language
и отобразим его в качестве вывода.
Измените маршрут query-example
в app.py
, указав следующий код:
@app.route('/query-example')
def query_example():
# if key doesn't exist, returns None
language = request.args.get('language')
return '''<h1>The language value is: {}</h1>'''.format(language)
Затем запустите приложение и перейдите по URL-адресу:
http://127.0.0.1:5000/query-example?language=Python
Браузер должен отобразить следующее сообщение:
OutputThe language value is: Python
Аргумент из URL присваивается переменной language
, а затем возвращается в браузер.
Чтобы добавить дополнительные параметры строки запроса, вы можете добавить амперсанд и новые пары ключ-значение в конец URL-адреса. Создайте ключ framework
и значение Flask
:
http://127.0.0.1:5000/query-example?language=Python&framework=Flask
И если вы хотите больше, продолжайте добавлять амперсанд и пары ключ-значение. Создайте ключ website
и значение DigitalOcean
:
http://127.0.0.1:5000/query-example?language=Python&framework=Flask&website=DigitalOcean
Чтобы получить доступ к этим значениям, вы по-прежнему будете использовать либо request.args.get()
, либо request.args[]
. Давайте используем оба, чтобы продемонстрировать, что происходит, когда отсутствует ключ. Измените маршрут query_example
, чтобы присвоить значение результатов переменным, а затем отобразить их:
@app.route('/query-example')
def query_example():
# if key doesn't exist, returns None
language = request.args.get('language')
# if key doesn't exist, returns a 400, bad request error
framework = request.args['framework']
# if key doesn't exist, returns None
website = request.args.get('website')
return '''
<h1>The language value is: {}</h1>
<h1>The framework value is: {}</h1>
<h1>The website value is: {}'''.format(language, framework, website)
Затем запустите приложение и перейдите по URL-адресу:
http://127.0.0.1:5000/query-example?language=Python&framework=Flask&website=DigitalOcean
Браузер должен отобразить следующее сообщение:
OutputThe language value is: Python
The framework value is: Flask
The website value is: DigitalOcean
Удалите ключ language
из URL:
http://127.0.0.1:5000/query-example?framework=Flask&website=DigitalOcean
Браузер должен отображать следующее сообщение с None
, когда значение для language
не указано:
OutputThe language value is: None
The framework value is: Flask
The website value is: DigitalOcean
Удалите ключ framework
из URL-адреса:
http://127.0.0.1:5000/query-example?language=Python&website=DigitalOcean
Браузер должен столкнуться с ошибкой, поскольку он ожидает значение для framework
:
Outputwerkzeug.exceptions.BadRequestKeyError
werkzeug.exceptions.BadRequestKeyError: 400 Bad Request: The browser (or proxy) sent a request that this server could not understand.
KeyError: 'framework'
Теперь вы понимаете, как обрабатывать строки запросов. Перейдем к следующему типу входящих данных.
Использование данных формы
Данные формы поступают из формы, которая была отправлена как POST-запрос на маршрут. Таким образом, вместо того, чтобы видеть данные в URL-адресе (за исключением случаев, когда форма отправляется с запросом GET), данные формы будут переданы в приложение за кулисами. Несмотря на то, что вы не можете легко увидеть передаваемые данные формы, ваше приложение все равно может их прочитать.
Чтобы продемонстрировать это, измените маршрут form-example
в app.py
, чтобы он принимал запросы GET и POST и возвращал форму:
# allow both GET and POST requests
@app.route('/form-example', methods=['GET', 'POST'])
def form_example():
return '''
<form method="POST">
<div><label>Language: <input type="text" name="language"></label></div>
<div><label>Framework: <input type="text" name="framework"></label></div>
<input type="submit" value="Submit">
</form>'''
Затем запустите приложение и перейдите по URL-адресу:
http://127.0.0.1:5000/form-example
Браузер должен отображать форму с двумя полями ввода — одно для language
и одно для framework
— и кнопку отправки.
Самое важное, что нужно знать об этой форме, это то, что она выполняет запрос POST к тому же маршруту, который сгенерировал форму. Все ключи, которые будут считаны в приложении, берутся из атрибутов name
в наших входных данных формы. В этом случае language
и framework
— это имена входных данных, поэтому у вас будет доступ к ним в приложении.
Внутри функции просмотра вам нужно будет проверить, является ли метод запроса GET или POST. Если это запрос GET, вы можете отобразить форму. В противном случае, если это запрос POST, вам нужно будет обработать входящие данные.
Измените маршрут form-example
в app.py
с помощью следующего кода:
# allow both GET and POST requests
@app.route('/form-example', methods=['GET', 'POST'])
def form_example():
# handle the POST request
if request.method == 'POST':
language = request.form.get('language')
framework = request.form.get('framework')
return '''
<h1>The language value is: {}</h1>
<h1>The framework value is: {}</h1>'''.format(language, framework)
# otherwise handle the GET request
return '''
<form method="POST">
<div><label>Language: <input type="text" name="language"></label></div>
<div><label>Framework: <input type="text" name="framework"></label></div>
<input type="submit" value="Submit">
</form>'''
Затем запустите приложение и перейдите по URL-адресу:
http://127.0.0.1:5000/form-example
Заполните поле language
значением Python
и поле framework
значением Flask
. Затем нажмите Отправить.
Браузер должен отобразить следующее сообщение:
OutputThe language value is: Python
The framework value is: Flask
Теперь вы понимаете, как обрабатывать данные формы. Перейдем к следующему типу входящих данных.
Использование данных JSON
Данные JSON обычно создаются процессом, который вызывает маршрут.
Пример объекта JSON выглядит следующим образом:
{
"language" : "Python",
"framework" : "Flask",
"website" : "Scotch",
"version_info" : {
"python" : "3.9.0",
"flask" : "1.1.2"
},
"examples" : ["query", "form", "json"],
"boolean_test" : true
}
Эта структура позволяет передавать гораздо более сложные данные, чем строки запроса и данные формы. В примере вы видите вложенные объекты JSON и массив элементов. Flask может обрабатывать этот формат данных.
Измените маршрут form-example
в app.py
, чтобы он принимал запросы POST и игнорировал другие запросы, такие как GET:
@app.route('/json-example', methods=['POST'])
def json_example():
return 'JSON Object Example'
В отличие от веб-браузера, используемого для строк запроса и данных формы, в целях этой статьи для отправки объекта JSON вы будете использовать Postman для отправки пользовательских запросов на URL-адреса.
Примечание. Если вам нужна помощь в навигации по интерфейсу Postman для запросов, обратитесь к официальной документации.
В Postman добавьте URL-адрес и измените тип на POST. На вкладке body измените значение на raw и выберите JSON в раскрывающемся списке.
Эти настройки необходимы, чтобы Postman мог правильно отправлять данные JSON, и чтобы ваше приложение Flask понимало, что оно получает JSON:
POST http://127.0.0.1:5000/json-example
Body
raw JSON
Затем скопируйте предыдущий пример JSON в текстовый ввод.
Отправьте запрос, и вы должны получить в качестве ответа Пример объекта JSON
. Это довольно антиклиматически, но этого следовало ожидать, потому что код для обработки ответа данных JSON еще не написан.
Чтобы прочитать данные, вы должны понимать, как Flask переводит данные JSON в структуры данных Python:
- Все, что является объектом, преобразуется в словарь Python.
{key : value}
в JSON соответствуетsomedict[key]
, который возвращает значение в Python. - Массив в JSON преобразуется в список в Python. Поскольку синтаксис тот же, вот пример списка:
[1,2,3,4,5]
- Значения внутри кавычек в объекте JSON становятся строками в Python.
- Булевы значения
true
иfalse
становятсяTrue
иFalse
в Python. - Наконец, числа без кавычек в Python становятся числами.
Теперь давайте поработаем над кодом для чтения входящих данных JSON.
Во-первых, давайте назначим все из объекта JSON в переменную, используя request.get_json()
.
request.get_json()
преобразует объект JSON в данные Python. Давайте назначим данные входящего запроса переменным и вернем их, внеся следующие изменения в маршрут json-example
:
# GET requests will be blocked
@app.route('/json-example', methods=['POST'])
def json_example():
request_data = request.get_json()
language = request_data['language']
framework = request_data['framework']
# two keys are needed because of the nested object
python_version = request_data['version_info']['python']
# an index is needed because of the array
example = request_data['examples'][0]
boolean_test = request_data['boolean_test']
return '''
The language value is: {}
The framework value is: {}
The Python version is: {}
The item at index 0 in the example list is: {}
The boolean value is: {}'''.format(language, framework, python_version, example, boolean_test)
Обратите внимание, как вы получаете доступ к элементам, которые не находятся на верхнем уровне. [версия][python]
используется, потому что вы вводите вложенный объект. И [examples][0]
используется для доступа к 0-му индексу в массиве примеров.
Если объект JSON, отправленный с запросом, не имеет ключа, к которому осуществляется доступ в вашей функции представления, запрос завершится ошибкой. Если вы не хотите, чтобы произошел сбой, когда ключ не существует, вам придется проверить, существует ли ключ, прежде чем пытаться получить к нему доступ.
# GET requests will be blocked
@app.route('/json-example', methods=['POST'])
def json_example():
request_data = request.get_json()
language = None
framework = None
python_version = None
example = None
boolean_test = None
if request_data:
if 'language' in request_data:
language = request_data['language']
if 'framework' in request_data:
framework = request_data['framework']
if 'version_info' in request_data:
if 'python' in request_data['version_info']:
python_version = request_data['version_info']['python']
if 'examples' in request_data:
if (type(request_data['examples']) == list) and (len(request_data['examples']) > 0):
example = request_data['examples'][0]
if 'boolean_test' in request_data:
boolean_test = request_data['boolean_test']
return '''
The language value is: {}
The framework value is: {}
The Python version is: {}
The item at index 0 in the example list is: {}
The boolean value is: {}'''.format(language, framework, python_version, example, boolean_test)
Запустите приложение и отправьте пример запроса JSON с помощью Postman. В ответ вы получите следующий вывод:
OutputThe language value is: Python
The framework value is: Flask
The Python version is: 3.9
The item at index 0 in the example list is: query
The boolean value is: false
Теперь вы понимаете, как обращаться с объектами JSON.
Заключение
В этой статье вы создали приложение Flask с тремя маршрутами, которые принимают строки запроса, данные формы или объекты JSON.
Кроме того, помните, что все подходы должны были учитывать повторяющееся соображение относительно корректного отказа при отсутствии ключа.
Предупреждение. Одной из тем, не затронутой в этой статье, была очистка пользовательского ввода. Дезинфекция пользовательского ввода гарантирует, что данные, считанные приложением, не приведут к неожиданному сбою или обходу мер безопасности.
Если вы хотите узнать больше о Flask, посетите нашу страницу темы Flask для упражнений и проектов по программированию.