DevGang
Авторизоваться

Как получить и проанализировать тело 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 может быть извлечено непосредственно из самого запроса, и в зависимости от кодировки вы получите доступ к соответствующему полю:

  1. request.json или request.get_json()
  2. request.form
  3. 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, которые не подбираются автоматически.

Источник:

#Flask #Python
Комментарии
Чтобы оставить комментарий, необходимо авторизоваться

Присоединяйся в тусовку

Vladimir Shaitan - Видео блог о frontend разработке и не только

Посмотреть