备注

当前文档对应的版本为 ESP-IDF v5.5.0

HTTP Client 示例

[English]

示例说明

本示例展示如何在 ESP32 上配置 HTTP 客户端,并通过 HTTP 与服务器建立连接,演示请求发送、响应接收及事件回调的基本操作。通过该示例,开发者可以学习 HTTP 客户端在不同配置方式下的初始化流程、结构体成员的使用方法以及事件回调处理机制,为后续实现具体 HTTP 请求和响应处理提供参考。

运行方法

示例完整代码见 http client 示例。示例配置及运行步骤详见 examples 目录下的 README.md 文件,在运行前需要通过 menuconfig 正确设置 Wi-Fi SSID 和密码,使设备能够成功连接网络。

头文件说明

本示例所使用的头文件涵盖了系统、网络、FreeRTOS 和 HTTP/TLS 模块,构建了任务调度与安全网络通信的核心功能。

各头文件按功能分类如下:

  1. 标准 C 库功能:提供字符串处理、内存管理、字符类型判断和系统参数宏等基础功能。

#include <string.h>
#include <sys/param.h>
#include <stdlib.h>
#include <ctype.h>
  1. 系统和日志:提供系统控制和日志功能,用于打印日志、获取系统信息以及执行系统操作。

#include "esp_log.h"
#include "esp_system.h"
  1. NVS 存储:提供非易失性存储功能,用于初始化和管理 NVS 数据。

#include "nvs_flash.h"
  1. 网络和事件:提供网络接口初始化和事件循环机制,用于初始化网络、处理网络事件和事件循环管理。

#include "esp_event.h"
#include "esp_netif.h"
  1. TLS/HTTP 和 HTTP 客户端:提供 HTTP/HTTPS 客户端和安全连接功能,用于发送请求、接收响应以及证书验证。其中证书验证为可选头文件,仅在需要 HTTPS 证书验证以保证连接安全时使用。

#include "esp_tls.h"
#if CONFIG_MBEDTLS_CERTIFICATE_BUNDLE
#include "esp_crt_bundle.h"
#endif
#include "esp_http_client.h"
  1. FreeRTOS 相关:提供实时操作系统功能,用于任务创建、调度和内核操作。

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
  1. 示例辅助:提供示例辅助功能,用于快速初始化网络和处理示例中的通用操作。

#include "protocol_examples_common.h"
#include "protocol_examples_utils.h"

宏定义说明

本示例通过宏定义设置了 HTTP 数据接收和输出缓冲区的大小,单位为字节:

#define MAX_HTTP_RECV_BUFFER 512      // 定义每次接收 HTTP 响应数据的缓冲区大小
#define MAX_HTTP_OUTPUT_BUFFER 2048   // 定义存储处理 HTTP 响应数据的缓冲区大

外部常量说明

本示例通过外部常量定义了 根证书 相关数据,用于 HTTPS 请求中进行服务器证书验证,保证安全连接。

  1. howsmyssl.com 根证书地址:指向程序里嵌入的 howsmyssl.com 根证书的开始和结束位置,用于验证 ESP32 访问对应网站时的服务器身份,保证连接安全。该网站主要用于测试 ESP32 的 HTTPS 请求功能。

extern const char howsmyssl_com_root_cert_pem_start[] asm("_binary_howsmyssl_com_root_cert_pem_start");
extern const char howsmyssl_com_root_cert_pem_end[]   asm("_binary_howsmyssl_com_root_cert_pem_end");
  1. postman 根证书地址:指向程序里嵌入的 postman 根证书的开始和结束位置,用于验证 ESP32 访问 Postman Echo API 或其它 Postman 提供的测试服务器时的身份,便于演示发送 HTTP 请求并接收响应的过程。

extern const char postman_root_cert_pem_start[] asm("_binary_postman_root_cert_pem_start");
extern const char postman_root_cert_pem_end[]   asm("_binary_postman_root_cert_pem_end");

备注

示例中使用的两个网站仅用于演示。实际项目中,如果需要访问其他 HTTPS 服务器,应提供对应服务器的根证书。

任务函数说明

在该示例中,除事件回调函数外,其余任务函数均展示了 HTTP/S 客户端执行的完整流程,包括 esp_http_client_config_t 结构体的配置和请求操作的执行。示例通过配置结构体的不同成员,演示如何根据具体应用需求完成客户端配置与请求操作:

  • HTTP URL 配置

  • Basic 认证配置

  • Digest 认证配置

  • HTTPS URL 配置

  • 查询参数编码

  • 不同重定向类型配置

  • 跨协议重定向配置

  • 分块传输数据

  • 流式读取数据

  • 异步请求处理

  • 访问无效 URL

  • 使用底层 API

  • 部分内容下载

esp_http_client_config_t 的具体结构体成员可参考 ESP HTTP API。配置说明可参考 HTTP 结构体配置说明。各请求操作的执行逻辑可参考 请求操作说明。整体函数逻辑相对简洁,其核心目的是展示从配置到请求的完整流程,帮助开发者理解在不同场景下如何选择合适的配置方式并验证其效果。

事件回调函数

_http_event_handler() 用于处理 HTTP 客户端在请求过程中出发的各类事件。通过该函数,应用层可以在不同阶段获取状态信息、接收数据或执行必要的资源管理操作。客户端可能触发的事件可参考 事件处理

示例代码仅展示了部分常用处理方式,其中部分事件仅进行了日志打印,主要用于演示事件触发过程,实际应用中可根据需求自行扩展为数据解析、错误恢复或自定义资源管理等操作。

其执行逻辑为:

  1. 创建变量

  • 创建变量 output_buffer 用于存储 HTTP 响应主体数据,即服务器在响应中返回的实际数据。

  • 创建变量 output_len 记录已接收数据的长度,用于控制数据复制的位置和避免越界访问。

  1. 事件处理:接收到事件后,进入事件处理流程,根据事件类型执行相应的操作。

  • HTTP_EVENT_ERROR 表示请求过程中发生错误。通常在连接失败、读写错误或底层 TLS/传输错误时触发。

  • HTTP_EVENT_ON_CONNECTED 成功建立 TCP 或 TLS 连接后触发。

  • HTTP_EVENT_HEADER_SENT 请求头部已发送完毕时触发。

  • HTTP_EVENT_ON_HEADER 接收到单个响应头字段时触发。

  • HTTP_EVENT_ON_DATA 接收到响应体的一个数据片段时触发。对于较大或分块传输的响应,该事件会多次触发,每次提供一段数据。

    • 清理缓冲区:如果当前是首次写入且调用方(即应用层代码)提供了 user_data 缓冲区,则将该缓冲区清零,避免残留数据,确保为新请求准备干净空间。

    • chunk 编码 判断,示例中仅提供非 chunk 编码时的处理逻辑。

    • 选择目标缓冲区并计算可复制长度:

      • 若调用方提供 user_data 缓冲区,使用 MIN() 计算本次可写入 user_data 的最大字节数,防止越界,并将当前片段复制到 user_data 的适当位置。

      • 若调用方未提供 user_data 缓冲区,则申请动态缓冲区 output_buffer

        • 调用 esp_http_client_get_content_length() 获取响应的总长度,用于一次性分配足够的堆内存。相关使用及参数说明可参考 ESP HTTP 客户端 API

        • 根据响应长度动态分配缓冲区内存,确保内存分配成功。

        • 使用 MIN() 计算本次可写入 output_buffer 的最大字节数,防止越界,并将当前片段复制到 output_buffer 的适当位置。

    • 更新接收长度。

  • HTTP_EVENT_ON_FINISH 响应接收完成且请求处理结束时触发,适合做最终清理或对完整响应的处理。

    • 如果分配了动态内存,则将其释放。

    • 重置接收长度,为下一次请求做准备。

  • HTTP_EVENT_DISCONNECTED 连接断开时触发,可能是正常断开也可能由错误导致。适用于记录底层错误并进行资源清理。

    • 调用 esp_tls_get_and_clear_last_error() 从底层 TLS 层获取最后的错误码并清除,分离出 ESP 错误码和 MbedTLS 错误码,打印详细错误信息,便于排查连接或证书问题。相关使用及参数说明可参考 ESP TLS API

    • 如果分配了动态内存,则将其释放,并重置接收长度,为下一次请求做准备。

  • HTTP_EVENT_REDIRECT 当收到 3xx 重定向响应 状态码且设定为手动重定向时触发,可以在回调中修改请求头或显式允许/拒绝重定向操作。

HTTP 客户端配置与执行

其余任务函数的执行逻辑相同,因此不逐一说明,仅对各函数在结构体配置和使用场景上的差异进行说明。HTTP 客户端的标准执行流程可参考 HTTP 客户端执行流程

HTTP URL 配置

  • http_rest_with_url() 演示配置完成后,通过完整 URL 修改 URL 后发起多种 HTTP 请求,并处理服务器响应的过程。

  • http_rest_with_hostname_path() 演示配置完成后,通过部分字段(hostpath 等)修改 URL 后发起多种 HTTP 请求,并处理服务器响应的过程。

在以上示例中,因为每次请求访问的资源或接口不同,所以每次设置请求方法前需要先调用 esp_http_client_set_url() 重新设定访问地址。相关使用及参数说明可参考 ESP HTTP 客户端 API

通过两种方法重新设定访问地址,体现了 URL 配置方式的灵活性:

  • 完整 URL 方式直观,适合在应用中直接指定访问目标(包含协议、主机、端口和路径),便于快速验证或访问固定资源。

  • 主机和路径 方式更灵活,主机部分保持不变时,只需修改路径即可访问不同资源,适合需要频繁切换同一服务器下的接口或资源的场景。

这种设计展示了 ESP HTTP 客户端既能支持简洁直接的配置,又能满足分场景复用和动态切换资源的需求。

Basic 认证配置:启用 CONFIG_ESP_HTTP_CLIENT_ENABLE_BASIC_AUTH 时执行。

  • http_auth_basic() 演示了标准 Basic 认证流程。

  • http_auth_basic_redirect() 演示了 Basic 认证在重定向场景下的处理,在未额外配置认证类型或重试次数,客户端依然能处理服务器返回的认证挑战。

有关 Basic 认证的说明可参考 Basic 认证。相关结构体配置说明可参考 HTTP 认证与安全配置 小节中的 认证机制配置 部分。

Digest 认证配置:启用 CONFIG_ESP_HTTP_CLIENT_ENABLE_DIGEST_AUTH 时执行。

  • http_auth_digest_md5() 演示通过 MD5 算法完成 Digest 认证。

  • http_auth_digest_sha256() 演示通过 SHA-256 算法完成 Digest 认证。

有关 Digest 认证的说明可参考 Digest 认证

在以上示例中,为了演示 Digest 认证,客户端通过不同 URL 触发服务器返回相应的认证挑战。

但需要注意,客户端设置的 URL 路径本身并不能决定服务器是否返回认证挑战,也无法指定摘要算法类型。Digest 认证流程由客户端和服务器共同完成,开发者只需根据响应码判断状态并执行相应处理。 同时,Digest 认证并不依赖于 esp_http_client_config_t 的特定成员配置,但如果使用 SHA-256 算法完成认证,由于该算法认证头比 MD5 长,默认发送缓冲区可能不足以容纳完整请求头,因此需修改结构体成员 buffer_size_tx 以增大发送缓冲区,保证认证请求能够正确发送。

HTTPS URL 配置

  • https_with_url() 演示通过完整 URL 发起 HTTPS 请求,并处理服务器响应的过程。

  • https_with_hostname_path() 演通过部分字段(hostpath 等)发起 HTTPS 请求,并处理服务器响应的过程。

在以上示例中,演示了通过不同方法配置 URL,配置方法的具体说明可参考 HTTP 认证与安全配置 小节中的 URL 配置 部分。

在访问 HTTPS 服务时,必须进行 TLS 握手并验证服务器证书。以上示例还分别展示了根证书的多种配置方式,其中 https_with_url() 使用系统预编译好的证书捆绑(bundle)来验证服务器证书,仅在启用 CONFIG_MBEDTLS_CERTIFICATE_BUNDLE 宏时执行。具体说明可参考 HTTP 认证与安全配置 小节中的 服务器证书验证 部分。

此示例的 PEM 格式证书通过外部变量获取,请查看 外部常量说明

查询参数编码

  • http_encoded_query() 演示了带特殊字符的查询参数如何进行 URL 编码,并在 HTTP GET 请求中正确使用。

有关 URL 编码的具体说明可参考 URL 编码

该示例执行流程如下:

  1. 通过 hostpath 配置 HTTP 客户端。

  2. 创建两个字符串变量,分别用于存储原始查询参数以及 URL 编码后的查询参数。

  3. 调用 example_uri_encode() 对原始查询参数进行 URL 编码,并返回编码后字符串长度,为 0 或负值时表示编码失败。

  4. 如果编码成功,打印编码结果,帮助调试,并将编码后的字符串存入配置结构体的 query 成员,有关该成员的详细说明可参考 HTTP 认证与安全配置 小节中的 URL 配置 部分。

  5. 使用配置结构体发起请求,并获取服务器响应。

备注

在示例中,编码结果被存储在固定长度的缓冲区中,因此需要确保该缓冲区足够大,以容纳编码后可能扩展的字符串,避免发生缓冲区溢出或数据截断的风险。

不同重定向类型配置

  • http_relative_redirect() 演示 相对路径 重定向的自动处理流程。

  • http_absolute_redirect() 演示 绝对路径 重定向的自动处理流程。

  • http_absolute_redirect_manual() 演示绝对路径重定向的 手动处理 流程。

有关重定向类型的说明可参考 重定向类型。有关重定向手动处理的说明及结构体配置可参考 自动重定向行为

在以上示例中,为了演示不同重定向类型,客户端分别使用了不同 URL,其中 path 部分根据重定向类型设置,以便触发服务器返回相应的 Location,从而稳定重现相对路径和绝对路径重定向的处理流程。

但需要注意,客户端设置的 URL 路径本身并不能决定服务器返回的重定向类型,服务器返回相对路径或绝对路径完全取决于其接口实现。示例中所使用的路径(即 /relative-redirect/3/absolute-redirect/3)实际上对应服务器上预先设计的测试接口,用于固定返回相对或绝对路径的 Location,从而保证能够稳定演示不同的重定向场景。 同时,重定向类型并不依赖于 esp_http_client_config_t 的结构体成员配置,客户端只负责按照服务器返回的 Location 生成并发起新的请求。

跨协议重定向配置

  • http_relative_redirect() 通过将目标指定为 HTTPS 地址,演示了从 HTTP 重定向到 HTTPS 的场景。

在该示例中,客户端通过 URL 触发服务器返回一个重定向到 HTTPS 的 Location,从而演示客户端如何处理跨协议重定向。需要注意的是,重定向目标本身并不取决于客户端的 URL,而是由服务器在响应头的 Location 字段决定。示例中设置特定的 URL,只是利用服务器提供的测试接口,确保返回的重定向目标为 HTTPS,从而稳定演示跨协议重定向的处理流程,而并非客户端能够直接控制服务器返回 HTTPS。

当客户端收到指向 HTTPS 的 Location 并发起新的请求时,必须进行 TLS 握手并验证服务器证书。如果未预先配置可信根证书,TLS 验证将失败,导致请求无法完成。因此,为了支持可能的跨协议重定向,客户端需要在配置 esp_http_client_config_t 结构体时提前设置证书信息,以保证在自动跟随重定向时能够正确验证服务器身份。具体说明可参考 HTTP 认证与安全配置 小节中的 服务器证书验证 部分。此示例通过 cert_pem 配置,证书通过外部变量获取,请查看 外部常量说明

分块传输数据

  • http_download_chunk() 演示了 ESP32 使用 HTTP 客户端进行分块传输下载的基本流程。

分块传输数据是服务器将响应体分成若干块逐步发送,客户端按块接收和处理的一种传输方式。进一步说明可参考 分块传输编码

在该示例中,客户端通过 URL 触发服务器返回分块传输响应。每当服务器发送一个数据块,HTTP 客户端就触发 HTTP_EVENT_ON_DATA 事件回调,并在回调中处理当前接收到的数据块。

需要注意,客户端设置的 URL 路径本身并不能决定服务器是否返回分块传输响应,同时,分块传输响应并不依赖于 esp_http_client_config_t 的结构体成员配置,客户端只需通过事件回调设置分块数据的处理逻辑。

流式读取数据

  • http_perform_as_stream_reader() 演示了 ESP32 通过底层 API 执行流式读取,获取完整响应的过程。

有关流式传输的说明及执行流程可参考 请求操作说明 小节中的 流式传输 部分。

异步请求处理

  • https_async() 演示如何在 ESP-IDF 中使用 esp_http_client 发起异步 HTTPS 请求,包括 POST 和 HEAD 方法。

有关异步请求的说明可参考 异步请求

结构体中的主要配置包括:

  • 配置异步模式相关成员,具体可参考 请求行为配置 小节中的 异步模式 部分。

  • 配置相应根证书以验证服务器,具体说明可参考 HTTP 认证与安全配置 小节中的 服务器证书验证 部分。

程序执行过程中需要循环调用 esp_http_client_perform() 以确保请求完成。相关使用及参数说明可参考 ESP HTTP 客户端 API

在本示例中,发送 POST 请求后程序调用 esp_http_client_cleanup() 释放了 HTTPS 客户端占用的资源,因此在执行后续 GET 请求前,需要重新初始化客户端并应用配置。相关使用及参数说明可参考 ESP HTTP 客户端 API

访问无效 URL

  • https_with_invalid_url() 演示访问一个无效 URL 时的处理流程。

该示例通过将 URL 设置为一个不存在的 HTTPS 地址测试和演示当 URL 无效或不可访问时,ESP32 HTTP 客户端的错误处理和日志输出,用于帮助理解 HTTPS 请求失败时可能遇到的错误类型以及如何捕获。

执行结果如下:

I (4430) HTTP_CLIENT: HTTPS request with invalid url =>
E (4500) esp-tls: couldn't get hostname for :not.existent.url: getaddrinfo() returns 202, addrinfo=0x0
E (4500) esp-tls: Failed to open new connection
E (4510) transport_base: Failed to open a new connection
E (4510) HTTP_CLIENT: Connection failed, sock < 0
I (4520) HTTP_CLIENT: HTTP_EVENT_ERROR
E (4520) HTTP_CLIENT: Error perform http request ESP_ERR_HTTP_CONNECT
I (4530) HTTP_CLIENT: HTTP_EVENT_DISCONNECTED
I (4530) HTTP_CLIENT: Last esp error code: 0x8001
I (4530) HTTP_CLIENT: Last mbedtls failure: 0x0
I (4540) HTTP_CLIENT: Finish http example

日志打印显示当尝试访问不存在的 URL 时,客户端无法解析主机名,连接建立失败,并触发 HTTP_EVENT_ERRORHTTP_EVENT_DISCONNECTED 事件,但没有发生 TLS 层错误。

使用底层 API

  • http_native_request() 演示了 ESP32 通过底层 API 执行一次性读取,获取完整响应的过程。

该示例执行逻辑和 流式读取数据 示例基本一致,但在读取数据时使用了 esp_http_client_read_response() 将响应体一次性读取到缓冲区。相关使用及参数说明可参考 ESP HTTP 客户端 API

示例中演示了 GET 和 POST 请求。在 GET 请求完成后,需调用 esp_http_client_close() 断开连接,以便进行后续请求;在发起新的请求前,需要重新初始化客户端并应用配置。相关使用及参数说明可参考 ESP HTTP 客户端 API

部分内容下载

  • http_partial_download() 演示了如何通过 HTTPS 客户端下载远程文件的部分内容,而非整个文件。

这种方式利用了 HTTP/S 协议的 Range 请求头,允许客户端只请求文件的指定字节范围。只需在调用 esp_http_client_set_header() 传入 Range 请求头以及指定下载方式即可。相关使用及参数说明可参考 ESP HTTP 客户端 API。 示例中展示了三种常用的部分下载方式:

  • 排除文件开头的前 10 个字节:Range: bytes=10-,下载从第 11 个字节开始直到文件末尾的内容,可用于跳过文件头或实现断点续传。

  • 只下载文件末尾的 10 个字节:Range: bytes=-10,下载文件尾部的一小段数据,可用于校验文件完整性或获取文件末尾信息。

  • 下载文件中间的 11~20 字节:Range: bytes=11-20,精确下载文件中间的某一段数据,适合按块处理大文件或流式解析。

在执行中需要注意:

  • 并非所有服务器都支持 Range 请求,需确保服务器返回 206 Partial Content 响应。

  • 内容长度为响应体长度,而不是文件总长度,需要结合 HTTP/S 头部的 Content-Range 信息判断文件总大小。

集中调用函数

http_test_task() 是一个总入口函数,调用它即可依次执行示例中的各个 HTTP 任务函数,无需单独调用每个任务。

主函数说明

该函数作为程序入口,用于完成系统初始化、网络配置并执行各个任务函数。

其执行流程为:

  1. 初始化非易失性存储 NVS

  2. 调用 esp_netif_init() 初始化网络接口层 ESP-NETIF,准备 Wi-Fi 或以太网功能。

  3. 调用 esp_event_loop_create_default() 创建默认 事件循环,为系统及 MQTT 客户端事件处理提供基础。API 介绍及参数说明可参考 事件循环库

  4. 调用 example_connect() 配置并连接网络(Wi-Fi 或以太网),确保设备具备联网能力。

  5. 调用 xTaskCreate() 创建总入口函数 http_test_task()。进一步说明及使用示例可参考 动态创建任务