Как получить и проанализировать тело HTTP-сообщения в Flask-JSON и данные формы
Flask - отличная микро-инфраструктура для веб-разработки на Python, позволяющая работать с минимальным количеством ресурсов. Рабочий REST API можно обслужить за секунды с помощью нескольких строк кода:
from flask import Flask, request
app = Flask(__name__)
@app.route('/')
def hello():
return 'Hello!'
if __name__ == "__main__":
app.run()
Основой современной сети является протокол HTTP, который отправляет запросы и доставляет ответы. Чтобы различать намерения, стоящие за этими запросами, с задачами, которые вы выполняете, были связаны несколько «глаголов». Глаголы GET
используются для аннотирования запросов, в которых вы хотите получить ресурсы, глаголы POST
используются для запроса ресурсов, которые должны быть созданы с учетом полезной нагрузки (тела), глаголы DELETE
используются для запроса удаления ресурсов и т. д.
Если вы хотите создать ресурс на сервере, вы отправите запрос POST с телом, содержащим данные, которые вы отправляете на сервер.
В этом руководстве мы рассмотрим, как получить тело HTTP POST во Flask.
В общем, вы, скорее всего, будете публиковать данные JSON в API REST, который использует эти данные, или вы будете публиковать данные формы - попросив пользователя заполнить веб-форму, а затем отправить эти данные в другой API для обработки.
При отправке данных формы - обычно они кодируются как multipart/form-data
, а при отправке данных JSON - обычно кодируются как application/json
. Эта информация встроена в заголовок запроса POST, который вы также можете проверить. Для удобства - мы будем проверять заголовки запроса перед анализом данных.
При работе с запросами - request
модуль flask
позволяет отображать входящие HTTP-запросы. Тело запроса POST может быть извлечено непосредственно из самого запроса, и в зависимости от кодировки вы получите доступ к соответствующему полю:
request.json
илиrequest.get_json()
request.form
request.data
request.json
представляет JSON, отправленный как запрос с типом содержимого application/json
. Как вариант, вы можете использовать метод request.get_json()
. И доступ к самому полю, и метод возвращает dict
- с парами key-value
, присутствующими во входящем JSON.
Примечание поле .
и методы json
get_json()
будут работать только в том случае, если для Content-Type запроса POST установлено значение application/json
. Если это строка в формате JSON - этот подход не удастся и приведет к значению None
. Если вы не можете заставить клиента отправлять правильно закодированные данные, вы можете преобразовать входящую строку в JSON. Будет рассмотрено позже в руководстве.
request.form
представляет данные multipart/form-data
, полученные через веб-формы.
request.data
представляет собой строковое представление входящих данных. В общем - вы будете использовать это представление для преобразования в JSON, если вы не можете заставить клиента отправлять ожидаемый тип контента.
Получить POST JSON
Начнем с JSON - это наиболее часто используемый формат для передачи данных между API. Мы создадим простой обработчик маршрута, который получает запрос POST
на конечной точке /post_json
. Помните, что поле json
будет содержать значение только в том случае, если заголовки запроса должным образом аннотируют тело как полезную нагрузку application/json
.
Здесь мы также получим Content-Type из headers
и проверим, действительно ли отформатировано тело application/json
. Если нет - мы даже не будем пытаться извлекать JSON из запроса ( если мы это сделаем, он молча завершится ошибкой) и будет возвращено сообщение об ошибке:
from flask import Flask, request
# ...
@app.route('/post_json', methods=['POST'])
def process_json():
content_type = request.headers.get('Content-Type')
if (content_type == 'application/json'):
json = request.json
return json
else:
return 'Content-Type not supported!'
Если вы сейчас отправите запрос POST на свою конечную точку - вас встретит возвращенный json:
$ curl -X POST -H "Content-type: application/json" -d "{\"firstName\" : \"John\", \"lastName\" : \"Smith\"}" "localhost:5000/post_json"
Примечание. В зависимости от операционной системы и оболочки, которые вы используете, вы можете использовать '
вместо "
или даже пропустить escape-символы, такие как \
.
Это приводит к:
{"firstName":"John","lastName":"Smith"}
Потрясающе! Попробуем установить аргумент -H
другого типа - чтобы проверить, хорошо ли работает этап проверки:
$ curl -X POST -H "Content-type: multipart/form-data" -d "{\"firstName\" : \"John\", \"lastName\" : \"Smith\"}" "localhost:5000/post_json"
Это приводит к:
Content-Type not supported!
В качестве альтернативы get_json()
работает примерно так же:
from flask import Flask, request
# ...
@app.route('/post_json', methods=['POST'])
def process_json():
content_type = request.headers.get('Content-Type')
if (content_type == 'application/json'):
json = request.get_json()
return json
else:
return 'Content-Type not supported!'
Получить POST JSON из строки
До сих пор мы были теми, кто отправлял запрос, поэтому у нас была свобода изменить тип контента по своему усмотрению. Это может быть не всегда - и иногда вы можете столкнуться с запросом в формате JSON, которому не назначен правильный тип содержимого.
В этом случае - json
и get_json()
вообще не анализируют входящее тело как JSON - и в конечном итоге будут None
, из которjuj вы ничего не сможете извлечь. В таких случаях - вы можете использовать модуль json
для загрузки полученной строки в словарь (пары key-value
)!
Импортируем модуль и конвертируем входящие request.data
:
from flask import Flask, request, json
# ...
@app.route('/post_json', methods=['POST'])
def process_json():
data = json.loads(request.data)
return data
Теперь - независимо от того, отправляете ли вы кодированное тело text/plain
или кодированное тело application/json
- модуль json
может обрабатывать ввод. Если мы попытаемся отправить любой из этих запросов - они оба приведут к одному и тому же ответу:
$ curl -X POST -H "Content-type: application/json" -d "{\"firstName\" : \"John\", \"lastName\" : \"Smith\"}" "localhost:5000/post_json"
$ curl -X POST -H "Content-type: text/plain" -d "{\"firstName\" : \"John\", \"lastName\" : \"Smith\"}" "localhost:5000/post_json"
Они приводят к:
{"firstName":"John","lastName":"Smith"}
Получить форму POST
При заполнении форм - у вас есть ряд полей ввода и соответствующие им ярлыки. Под капотом - это просто пары key-value
:
username=user_input
password=user_input_2
...
Обычно это происходит из внешнего интерфейса - обычно это HTML-страница с тегом <form>
с несколькими полями <input>
внутри. Вы также можете отправить данные формы curl
:
$ curl -X POST -H "Content-type: multipart/form-data" -F "username=john" -F "password=doe" "localhost:5000/post_form"
Или вы можете свернуть все поля в один аргумент:
$ curl -X POST -H "Content-type: multipart/form-data" -F "username=john&password=doe" "localhost:5000/post_form"
В общем, вы будете работать с реальными формами, а форма, с которой мы будем работать, будет выглядеть так:
<form action="/post_form" enctype="multipart/form-data" method="POST">
<input type="text" name="username">
<input type="password" name="password">
</form>
name
каждого <input>
отображается как key
к value
, введенному пользователем. form
, извлеченная из объекта request
, является еще одним dict
, и вы можете легко получить доступ к полям по отдельности:
from flask import Flask, request
# ...
@app.route('/post_form', methods=['POST'])
def process_form():
data = request.form
print(data['username'])
print(data['password'])
return data
Когда мы отправляем запрос через консоль - возвращается словарь, содержащий пары ключ-значение (который затем снова форматируется как JSON):
{"password":"doe","username":"john"}
И на стороне сервера - данные для этих двух полей были набраны прямо под журналом входящего запроса.
127.0.0.1 - - [09/Dec/2021 00:24:32] "POST /post_form HTTP/1.1" 200 -
john
doe
Естественно, вместо того, чтобы просто выводить значения на консоль, вы должны проверить данные, создать пользователя и сохранить их в базе данных. В качестве альтернативы вы можете заполнить поля любого класса таким образом, прежде чем использовать этот класс по его назначению.
Вывод
В этом руководстве мы рассмотрели, как обрабатывать входящие запросы HTTP POST во Flask. Мы рассмотрели входящие данные JSON, а также то, как обрабатывать строковые JSON, которые не подбираются автоматически.