Программирование ARM ESP32-C3: клиент HTTP Sat, June 15 2024  

Поделиться

Нашли опечатку?

Пожалуйста, сообщите об этом - просто выделите ошибочное слово или фразу и нажмите Shift Enter.

ESP32-C3: клиент HTTP Печать
Добавил(а) microsin   

Компонент esp_http_client предоставляет набор API-функций для создания запросов HTTP/HTTPS из приложений ESP-IDF. Для использования клиента HTTP выполните следующие шаги:

esp_http_client_init(): создает экземпляр дескриптора клиента esp_http_client_handle_t, т. е. клиента HTTP на основе предоставленной конфигурации esp_http_client_config_t. Эта функция должна быть вызвана первой; подразумеваются значения по умолчанию для параметров конфигурации, которые не были явно определены пользователем.

esp_http_client_perform(): выполнит все операции esp_http_client - откроет соединение, осуществит обмен данными и закроет соединение (как это будет необходимо), блокируя выполнение вызывающей задачи до завершения этой функции. Все связанные с вызовом события будут переданы в обработчик (event handler, который был задан в конфигурации esp_http_client_config_t).

esp_http_client_cleanup(): закроет соединение (если оно было) и освободит всю память, которая была выделена для экземпляра клиента HTTP. Этот вызов должен быть последней используемой операцией API клиента HTTP.

Простой пример приложения, который использует ESP HTTP Client для создания запросов HTTP/HTTPS, можно найти в каталоге protocols/esp_http_client среди примеров ESP-IDF.

Базовый запрос HTTP. Посмотрите пример использования функций http_rest_with_url и http_rest_with_hostname_path в приложении примера esp_http_client.

Постоянные соединения. Постоянное соединение означает, что клиент HTTP может повторно использовать одно и то же соединение для нескольких обменов данными. Если сервер не запрашивает закрытие соединение через Connection: close заголовка, то соединение на отбрасывается, и вместо этого остается открытым, и будет использоваться для будущих запросов.

Чтобы клиент ESP HTTP мог воспользоваться всеми плюсами постоянных соединений, следует выполнить как можно больше запросов, используя один и тот же экземпляр дескриптора. Просмотрите использование функций http_rest_with_url и http_rest_with_hostname_path в приложении примера esp_http_client. Здесь создается одно соединение, и как только оно создано, делается несколько запросов (GET, POST, PUT и т. д.) перед закрытием соединения.

Запрос HTTPS. Клиент ESP HTTP поддерживает соединения SSL, используя библиотеку mbedTLS, с конфигурацией url, начинающейся со схемы https, или transport_type, установленным в HTTP_TRANSPORT_OVER_SSL. Поддержка HTTPS может быть сконфигурирована опцией menuconfig CONFIG_ESP_HTTP_CLIENT_ENABLE_HTTPS (Component config → ESP HTTP client → Enable https, эта опция разрешена по умолчанию).

Замечание: при выдаче запросов HTTPS, если нужна проверка сертификата сервера, то нужно предоставить дополнительный корневой сертификат (root certificate) в формате PEM для поля cert_pem структуры конфигурации esp_http_client_config_t. Пользователи также могут использовать ESP x509 Certificate Bundle для проверки сервера, используя для этого поле crt_bundle_attach структуры конфигурации esp_http_client_config_t.

См. использование функций https_with_url и https_with_hostname_path для подробностей реализации запроса HTTPS.

[HTTP Stream]

Некоторым приложениям нужно открыть соединение и активно управлять обменом данными (data streaming). В таких случаях поведение приложения отличается от поведения обычных запросов. Ниже показан пример поведения приложения:

esp_http_client_init(): создается дескриптор клиента HTTP.

esp_http_client_set_* или esp_http_client_delete_*: модифицируются параметры соединения HTTP (опциональный шаг).

esp_http_client_open(): открывается соединение HTTP с параметром write_len (длина содержимого, которое должно быть записано на сервер), устанавливается write_len=0 для соединения read-only.

esp_http_client_write(): записываются данные на сервер с максимальной длиной, равной write_len параметра функции esp_http_client_open(); для write_len=0 эту функцию вызывать не нужно.

esp_http_client_fetch_headers(): вычитывает заголовки ответа сервера HTTP, после отправки заголовков запроса и данных сервера (если таковые имеются). Возвращает content-length от сервера, и состояние операции может быть проверено esp_http_client_get_status_code(), чтобы получить HTTP status соединения.

esp_http_client_read(): чтение HTTP stream.

esp_http_client_close(): закрытие соединения.

esp_http_client_cleanup(): освобождение связанных ресурсов.

Для деталей реализации см. использование функции http_perform_as_stream_reader в приложении примера esp_http_client.

[Аутентификация HTTP]

Клиент ESP HTTP поддерживает оба вида аутентификации - базовая (Basic Authentication) и с цифровой подписью (Digest Authentication).

· Пользователи могут предоставить в имя пользователя (username) и пароль (password) напрямую в тексте ссылки (URL/URI), или заполнить поля username и password в структуре конфигурации esp_http_client_config_t. Для auth_type = HTTP_AUTH_TYPE_BASIC, клиент HTTP выполняет только одну операцию для прохождения процесса аутентификации.

· Если auth_type = HTTP_AUTH_TYPE_NONE, но в конфигурации были заполнены поля username и password, то клиент HTTP выполняет две операции. Клиент получит сообщение 401 Unauthorized header в ответ на свою первую попытку подключения к серверу. На основе этой информации клиент примет решение, какой метод аутентификации выбрать для второй операции.

Для подробностей реализации просмотрите использование функций http_auth_basic, http_auth_basic_redirect (для Basic Authentication) и http_auth_digest (для Digest Authentication) в приложении примера esp_http_client.

Примеры конфигурации аутентификации:

Аутентификация в ссылке (URI):

esp_http_client_config_t config = {
   .url = "http://user:passwd@httpbin.org/basic-auth/user/passwd",
   .auth_type = HTTP_AUTH_TYPE_BASIC,
};

Аутентификация путем заполнения полей username и password:

esp_http_client_config_t config = {
   .url = "http://httpbin.org/basic-auth/user/passwd",
   .username = "user",
   .password = "passwd",
   .auth_type = HTTP_AUTH_TYPE_BASIC,
};

[Обработка событий]

Клиент ESP HTTP поддерживает обработку событий путем запуска обработчика (event handler), соответствующего произошедшему событию. Перечисление esp_http_client_event_id_t содержит все события, которые могли бы произойти при выполнении запроса HTTP клиентом ESP HTTP.

Чтобы разрешить обработку событий, вам просто нужно установить указатель на функцию обратного вызова (callback) в поле event_handler структуры конфигурации esp_http_client_config_t.

Числовые значения событий кодируются в перечислении esp_http_client_event_id_t:

/**
 * @brief Идентификаторы событий клиента HTTP
 */
typedef enum
{
   HTTP_EVENT_ERROR = 0,       /*!< Это событие происходит, когда при выполнении возникает
                                    какая-нибудь ошибка. */
   HTTP_EVENT_ON_CONNECTED,    /*!< Происходит, когда произошло подключение к серверу HTTP,
                                    и еще не передавались никакие данные. */
   HTTP_EVENT_HEADERS_SENT,    /*!< После отправки всех заголовков с сервера HTTP. */
   HTTP_EVENT_HEADER_SENT = HTTP_EVENT_HEADERS_SENT, /*!< Это значение оставлено для сохранения
                                                          обратной совместимости, и в будущих
                                                          версиях ESP-IDF устареет. */
   HTTP_EVENT_ON_HEADER,       /*!< Происходит при получении каждого из заголовков. */
   HTTP_EVENT_ON_DATA,         /*!< Происходит при приеме данных с сервера, возможно несколькими
                                    порциями для одного пакета. */
   HTTP_EVENT_ON_FINISH,       /*!< Происходит при завершении сессии HTTP. */
   HTTP_EVENT_DISCONNECTED,    /*!< Соединение завершено, отключение от сервера HTTP. */
} esp_http_client_event_id_t;

Особый интерес представляет, на мой взгляд, событие HTTP_EVENT_ON_HEADER, потому что оно позволяет получить предварительную информацию о запрашиваемом web-ресурсе в виде заголовков. Эта информация может быть довольно полезна, потому что позволяет до загрузки данных ресурса оценить объем закачиваемых данных. Данные заголовков доступны в полях key и value параметра обработчика esp_http_client_event_t *evt. Значение evt->key возвращает имя параметра заголовка, а значение evt->value значение параметра.

Ниже приведен пример вывода информации о заголовков в событии HTTP_EVENT_ON_HEADER. Здесь было обращение к файлу firmware прошивки, который находился на сервере и был доступен для загрузки. Заголовок key=content-length, value=1593024 позволяет оценить размер файла в байтах, который предстоит загрузить:

I (2322) HTTP_EVENT_ON_HEADER, key=date, value=Thu, 06 Apr 2023 04:45:16 GMT
I (2322) HTTP_EVENT_ON_HEADER, key=server, value=uvicorn
I (2322) HTTP_EVENT_ON_HEADER, key=content-type, value=application/octet-stream
I (2322) HTTP_EVENT_ON_HEADER, key=content-length, value=1593024
I (2332) HTTP_EVENT_ON_HEADER, key=last-modified, value=Wed, 29 Mar 2023 21:39:21 GMT
I (2332) HTTP_EVENT_ON_HEADER, key=etag, value=1f5fbadd21103930ea58a0b969b457d9

Диагностика клиента ESP HTTP. Диагностическая информация может помочь разобраться в причине каких-либо проблем. В случае клиента ESP HTTP эта диагностическая информация может быть собрана регистрацией обработчика с библиотекой Event Loop. Этот функционал был добавлен с учетом того, что фреймворк ESP Insights собирается информацию диагностики. Однако этот функционал для целей диагностики также может использоваться без какой-либо зависимости от ESP Insights framework. Обработчик событий может быть зарегистрирован для цикла обработки событий (event loop) с помощью функции esp_event_handler_register().

Ожидаемые типы данных в event loop различных событий клиента HTTP:

HTTP_EVENT_ERROR: esp_http_client_handle_t
HTTP_EVENT_ON_CONNECTED: esp_http_client_handle_t
HTTP_EVENT_HEADERS_SENT: esp_http_client_handle_t
HTTP_EVENT_ON_HEADER: esp_http_client_handle_t
HTTP_EVENT_ON_DATA: esp_http_client_on_data_t
HTTP_EVENT_ON_FINISH: esp_http_client_handle_t
HTTP_EVENT_DISCONNECTED: esp_http_client_handle_t
HTTP_EVENT_REDIRECT: esp_http_client_redirect_event_data_t

Дескриптор esp_http_client_handle_t, полученный в данных события, будет достоверен до тех пор, пока не будет получено событие HTTP_EVENT_DISCONNECTED. Этот дескриптор должен быть отправлен главным образом для того, чтобы разделять между собой различные соединения клиента, и не должен использоваться для других целей (поскольку это может поменяться на основе состояния соединения клиента).

[Справочник API клиента HTTP]

Заголовочный файл: components/esp_http_client/include/esp_http_client.h.

Ниже в таблице приведен общий список API-функций клиента HTTP. Подробное описание параметров API-функций, структур, типов данных, перечислений и макросов см. в документации [1].

Функция Описание
esp_http_client_init Запустит сессию HTTP. Эта функция должна быть первым вызовом, и она возвратит значение дескриптора esp_http_client_handle_t, которое вам следует использовать в качестве входного параметра для других функций интерфейса клиента HTTP. Этот вызов ДОЛЖЕН быть комплементарным с последующим окончательным вызовом esp_http_client_cleanup, когда операция клиента завершена.
esp_http_client_perform Используйте эту функцию после успешного завершения esp_http_client_init и после всех вызовов для настройки опций. Эта функция выполнит транзакцию, как было описано в опицях(1). Она должна быть вызвана на входе с тем же значением esp_http_client_handle_t, которое было возвращено из вызова esp_http_client_init. Функция esp_http_client_perform выполняет весь запрос либо путем блокирования своего потока, либо без блокировки. По умолчанию API выполняет запрос с блокировкой, и выполнит возврат при завершении операции либо если запрос завершился неудачно, либо запрос будет выполнен без блокировки, и произойдет возврат если была ситуация EAGAIN/EWOULDBLOCK или EINPROGRESS, либо была неудача. И в случае не блокирующего запроса пользователь может выполнить этот вызов несколько раз, если запрос и ответ не выполнены, или не произошел сбой. Чтобы разрешить неблокирующую работу esp_http_client_perform(), поле is_async member структуры конфигурации esp_http_client_config_t должно быть установлено при вызове esp_http_client_init(). Вы можете сделать любое количество вызовов esp_http_client_perform при использовании того же самого значения дескриптора esp_http_client_handle_t. Нижележащее соединение может удерживаться открытым, если сервер это позволяет. Если вы намерены передать больше одного файла, то это даже поощряется. Компонент esp_http_client будет затем пытаться повторно использовать то же самое соединение для последующих передач, делая тем самым операции быстрее, уменьшая нагрузку на CPU и меньше задействуя сетевые ресурсы. Просто имейте в виду, что для установки параметров следующих esp_http_client_perform необходимо использовать esp_http_client_set_* * между вызовами.
esp_http_client_cancel_request Отменяет работающий запрос HTTP. Эта функция закроет текущий сокет и откроет новый сокет с тем же контекстом esp_http_client.
esp_http_client_set_url Установит URL для клиента. В опциях старый URL будет заменен на новый.
esp_http_client_set_post_field Установит данные post, эта функция должна быть вызвана перед esp_http_client_perform. Обратите внимание: параметр data, переданный в эту функцию, является указателем, и эта функция не делает копию этих данных.
esp_http_client_get_post_field Извлечет информацию текущего поля post.
esp_http_client_set_header Установит заголовок запроса http, эта функция должна быть вызвана после esp_http_client_init и перед выполнением любой функции.
esp_http_client_get_header Извлечет заголовок запроса http. Параметр value будет установлен в NULL, если здесь нет заголовка, который такой же, как указанный key, иначе адрес значения будет назначен параметру value. Эта функция должна быть вызвана после esp_http_client_init.
esp_http_client_get_username Извлечет имя пользователя (username) запроса http. Адрес буфера username будет назначен параметру value. Эта функция должна быть вызвана после esp_http_client_init.
esp_http_client_set_username Установит имя пользователя (username) запроса http. Значение параметра username будет присвоено буферу имени пользователя. Если параметр username NULL, то буфер имени пользователя будет освобожден.
esp_http_client_get_password Извлечет пароль (password) запроса http. Адрес буфера password будет назначен параметру value. Эта функция должна быть вызвана после esp_http_client_init.
esp_http_client_set_password Установит пароль (password) запроса http. Значение параметра password будет присвоено буферу пароля. Если параметр password NULL, то буфер пароля будет освобожден.
esp_http_client_set_authtype Установит тип аутентификации запроса http.
esp_http_client_get_user_data Извлечет данные пользователя запроса http. Значение, сохраненное из esp_http_client_config_t будет записано по адресу, переданному в параметре data.
esp_http_client_set_user_data Установит данные пользователя запроса http. Значение, переданное в data, будет доступно во время callback-вызовов событий. От имени пользователя не будет выполняться никакое обслуживание памяти.
esp_http_client_get_errno Извлечет номер ошибки (errno) сессии клиента HTTP.
esp_http_client_set_method Установит метод запроса http.
esp_http_client_set_timeout_ms Установит таймаут запроса http.
esp_http_client_delete_header Удалит заголовок запроса http.
esp_http_client_open Эта функция откроет соединение, запишет все строки заголовка и выполнит возврат.
esp_http_client_write Эта функция запишет данные в соединение HTTP, которое было ранее открыто esp_http_client_open().
esp_http_client_fetch_headers Эта функция должна быть вызвана после esp_http_client_open, она будет читать из http stream и обрабатывать все принятые заголовки.
esp_http_client_is_chunked_response Проверка данных ответа, поделены ли они они на куски.
esp_http_client_read Чтение данных из http stream(2).
esp_http_client_get_status_code Извлечение кода состояния ответа http, будет возвращено достоверное значение, если эта функция была вызвана после esp_http_client_perform.
esp_http_client_get_content_length Извлечет размер содержимого ответа http (из Content-Length заголовка). Будет возвращено достоверное значение, если эта функция была вызвана после esp_http_client_perform.
esp_http_client_close Закроет соединение http, сохраняя все выделенные ресурсы запроса http.
esp_http_client_cleanup Эта функция должна быть вызвана последней в сессии клиента. Она является комплементом функции esp_http_client_init, и она должна быть вызвана с тем же дескриптором в параметре, который был возвращен из esp_http_client_init. Вызов esp_http_client_cleanup может закрыть все соединения, связанные с этим дескриптором, которые возможно оставались открытыми до этого момента. Не вызывайте эту функцию, если намерены передать больше файлов, повторное использование дескрипторов это ключ к достижению хорошей производительности с компонентом esp_http_client.
esp_http_client_get_transport_type Извлечет тип транспорта.
esp_http_client_set_redirection Установит URL перенаправления. Когда принят код 30x с сервера, клиент сохраняет URL перенаправления, предоставленный сервером. Эта функция установит текущий URL на перенаправление, что позволит клиенту выполнить запрос перенаправления. Когда установлен disable_auto_redirect, клиент не будет вызывать эту функцию, однако событие HTTP_EVENT_REDIRECT будет маршрутизировано, предоставляя пользователю управление над событием перенаправления.
esp_http_client_add_auth При получении кода HTTP Status 401, этот вызов API может быть сделан для добавления информации авторизации.
esp_http_client_is_complete_data_received Проверяет, были ли прочитаны без ошибки все данные ответа.
esp_http_client_read_response Вспомогательная API-функция для чтения больших кусков данных. Эта API-функция вызывает несколько раз внутри себя esp_http_client_read, пока не достигнет конца данных, или пока буфер не будет заполнен.
esp_http_client_flush_response Обработает все оставшиеся данные ответа. Функция использует внутренний буфер для повторяющихся приемов, парсинга и отбрасывания данных ответа, пока не будут обработаны все данные. Не требуется дополнительного буфера, предоставленного пользователем, это может быть предпочтительнее esp_http_client_read_response в ситуациях, когда содержимое ответа может быть игнорировано.
esp_http_client_get_url Извлечет URL клиента.
esp_http_client_get_chunk_length Извлечет Chunk-Length клиента.

Примечания:

(1) Нельзя вызывать эту функцию одновременно из двух мест, используя один и тот же дескриптор клиента esp_http_client_handle_t. Пусть первый вызов завершится, прежде чем делать второй вызов. Если вы хотите делать параллельные транзакции, то должны использовать несколько дескрипторов esp_http_client_handle_t. Эта функция включает вызовы esp_http_client_open -> esp_http_client_write -> esp_http_client_fetch_headers -> esp_http_client_read (и как опция) esp_http_client_close.
(2) (-ESP_ERR_HTTP_EAGAIN = -0x7007) будет возвращено, когда произошел таймаут вызова до того, как данные стали готовы.

[Ссылки]

1. ESP-С3 HTTP Client site:espressif.com.

 

Добавить комментарий


Защитный код
Обновить

Top of Page