ESP32 IDF开发 应用篇⑱ esp_http_client实例分析
别迷路-导航栏
快速导航找到你想要的(文章目录)
此篇文章如果对你有用,请点赞收藏,您的支持就是博主坚持的动力。
1、博主写这篇技术文章的目的:
(1)、esp_http_client api的使用方法;
2、概述
在上一篇已经介绍了http的基本概念,这章主要介绍esp_http_client.c文件中封装好的api函数的使用。
3、esp_http_client相关API的介绍
这里介绍大部分esp_http_client库的使用更详细的请参考:更多API 参考esp-idf\components\esp_http_client\include\esp_http_client.h
(1)、esp_http_client的初始化
先来看看初始化API
/**
* @brief 启动HTTP会话
*此函数必须是第一个要调用的函数,它返回一个esp_http_client_handle_t,您必须将其用作接口中其他函数的输入。
*操作完成后,此调用必须对esp_http_client_cleanup进行相应的调用。
* @param [in] config配置,请参见`http_client_config_t`
* @return
*-`esp_http_client_handle_t`
*-如果有任何错误,则为NULL
*/
esp_http_client_handle_t esp_http_client_init(const esp_http_client_config_t *config);
再来解说初始化的内容有哪些
为结构体esp_http_client_config_t的参数分配内存,初始化数据
esp_http_client_handle_t esp_http_client_init(const esp_http_client_config_t *config)
{
_success = (
(client = calloc(1, sizeof(esp_http_client_t))) &&
(client->parser = calloc(1, sizeof(struct http_parser))) &&
(client->parser_settings = calloc(1, sizeof(struct http_parser_settings))) &&
(client->auth_data = calloc(1, sizeof(esp_http_auth_data_t))) &&
(client->request = calloc(1, sizeof(esp_http_data_t))) &&
(client->request->headers = http_header_init()) &&
(client->request->buffer = calloc(1, sizeof(esp_http_buffer_t))) &&
(client->response = calloc(1, sizeof(esp_http_data_t))) &&
(client->response->headers = http_header_init()) &&
(client->response->buffer = calloc(1, sizeof(esp_http_buffer_t)))
);
。。。。。
_success = (
(client->transport_list = esp_transport_list_init()) &&
(tcp = esp_transport_tcp_init()) &&
(esp_transport_set_default_port(tcp, DEFAULT_HTTP_PORT) == ESP_OK) &&
(esp_transport_list_add(client->transport_list, tcp, "http") == ESP_OK)
}
在esp_transport_tcp_init中注册了tcp的回调函数
tcp_connect, tcp_read, tcp_write, tcp_close, tcp_poll_read, tcp_poll_write, tcp_destroy
esp_transport_handle_t esp_transport_tcp_init(void)
{
esp_transport_set_func(t, tcp_connect, tcp_read, tcp_write, tcp_close, tcp_poll_read, tcp_poll_write, tcp_destroy);
}
(2)、设置url连接API
/**
* @brief 为客户端设置URL,执行此行为时,URL中的选项将替换旧的
*
* @param [in]客户端esp_http_client句柄
* @param [in] url URL
*
* @return
*-ESP_OK
*-ESP_FAIL
*/
esp_err_t esp_http_client_set_url(esp_http_client_handle_t client, const char *url);
解析esp_http_client_set_url主要是对对client->connection_info结构体的操作,将url分解到connection_info各个参数中
结构体connection_info_t
typedef struct {
char *url;
char *scheme;
char *host;
int port;
char *username;
char *password;
char *path;
char *query;
char *cert_pem;
esp_http_client_method_t method;
esp_http_client_auth_type_t auth_type;
esp_http_client_transport_t transport_type;
int max_store_header_size;
} connection_info_t;
(3)、设置请求方法
/**
* @brief设置http请求方法
*
* @param [in]客户端esp_http_client句柄
* @param [in]方法方法
*
* @return
*-ESP_OK
*-ESP_ERR_INVALID_ARG
*/
esp_err_t esp_http_client_set_method(esp_http_client_handle_t client, esp_http_client_method_t method);
请求方法:
/**
* @brief HTTP method
*/
typedef enum {
HTTP_METHOD_GET = 0, /*!< HTTP GET Method */
HTTP_METHOD_POST, /*!< HTTP POST Method */
HTTP_METHOD_PUT, /*!< HTTP PUT Method */
HTTP_METHOD_PATCH, /*!< HTTP PATCH Method */
HTTP_METHOD_DELETE, /*!< HTTP DELETE Method */
HTTP_METHOD_HEAD, /*!< HTTP HEAD Method */
HTTP_METHOD_NOTIFY, /*!< HTTP NOTIFY Method */
HTTP_METHOD_SUBSCRIBE, /*!< HTTP SUBSCRIBE Method */
HTTP_METHOD_UNSUBSCRIBE,/*!< HTTP UNSUBSCRIBE Method */
HTTP_METHOD_OPTIONS, /*!< HTTP OPTIONS Method */
HTTP_METHOD_MAX,
} esp_http_client_method_t;
(4)、设置post数据
/**
* @brief设置发布数据,必须在`esp_http_client_perform`之前调用此函数。
*注意:传递给此函数的data参数是一个指针,该函数不会复制数据
*
* @param [in]客户端esp_http_client句柄
* @param [in]数据发布数据指针
* @param [in] len帖子长度
*
* @return
*-ESP_OK
*-ESP_FAIL
*/
esp_err_t esp_http_client_set_post_field(esp_http_client_handle_t client, const char *data, int len);
(5)、esp_http_perform获得请求,完成TCP发送和接收
/*
esp_http_client_perform以阻塞或非阻塞方式执行整个请求。
默认情况下,API以阻塞方式执行请求,并在完成后返回,
*/
esp_err_t esp_http_client_perform(esp_http_client_handle_t client);
/**
* @brief 此函数将打开连接,写入所有标头字符串并返回
*
* @param [in]客户端esp_http_client句柄
* @param [in] write_len HTTP内容长度需要写入服务器
*
* @return
*-ESP_OK
*-ESP_FAIL
*/
esp_err_t esp_http_client_open(esp_http_client_handle_t client, int write_len);
/**
* @brief 该函数需要在esp_http_client_open之后调用,它将从http流中读取,处理所有接收头
*
* @param [in]客户端esp_http_client句柄
*
* @return
*-(0)如果流不包含内容长度标头或分块编码(由`esp_http_client_is_chunked`响应检查)
*-(-1:ESP_FAIL)如果有任何错误
*/
int esp_http_client_fetch_headers(esp_http_client_handle_t client);
4、软件设计
(1)、在连接好wifi之后首先就是填充结构体,结构体的内容如下:
/**
* @brief HTTP configuration
*/
typedef struct {
const char *url; /*!< HTTP URL,URL上的信息最重要,它将覆盖下面的其他字段*/
const char *host; /*!< 域名或IP作为字符串 */
int port; /*!< 用于连接的端口,默认取决于esp_http_client_transport_t(80或443)*/
const char *username; /*!< 用于Http身份验证 */
const char *password; /*!< 用于Http身份验证 */
esp_http_client_auth_type_t auth_type; /*!< Http身份验证类型,请参见`esp_http_client_auth_type_t` */
const char *path; /*!< HTTP路径(如果未设置),默认为`/`*/
const char *query; /*!< HTTP 查询 */
const char *cert_pem; /*!< SSL服务器认证,PEM格式为字符串(如果客户端要求验证服务器) */
const char *client_cert_pem; /*!< SSL客户端认证,PEM格式为字符串(如果服务器要求验证客户端) */
const char *client_key_pem; /*!< SSL客户端密钥,PEM格式为字符串(如果服务器要求验证客户端) */
esp_http_client_method_t method; /*!< HTTP方法 */
int timeout_ms; /*!< 网络超时(以毫秒为单位) */
bool disable_auto_redirect; /*!< 禁用HTTP自动重定向 */
int max_redirection_count;/*!< 最大重定向数,如果为零,则使用默认值*/
http_event_handle_cb event_handler; /*!< HTTP事件处理 */
esp_http_client_transport_t transport_type; /*!< HTTP传输类型,请参见`esp_http_client_transport_t` */
int buffer_size; /*!< HTTP接收缓冲区大小 */
int buffer_size_tx; /*!< HTTP传输缓冲区大小 */
void *user_data; /*!< HTTP user_data上下文 */
bool is_async; /*!< 设置异步模式,目前仅支持HTTPS*/
bool use_global_ca_store;/*!< Use a global ca_store for all the connections in which this bool is set. */
bool skip_cert_common_name_check;/*!< 跳过对服务器证书CN字段的任何验证 */
} esp_http_client_config_t;
给结构体赋值,并且注册回调函数检测状态
esp_http_client_config_t config = {
.url = “http://httpbin.org/get”,
.event_handler = _http_event_handler,
};
初始化结构体,注册tcp读写连接函数
esp_http_client_handle_t client = esp_http_client_init(&config);
esp_http_client默认就是GET方法,其他方法如下
/**
* @brief HTTP method
*/
typedef enum {
HTTP_METHOD_GET = 0, /*!< HTTP GET Method */
HTTP_METHOD_POST, /*!< HTTP POST Method */
HTTP_METHOD_PUT, /*!< HTTP PUT Method */
HTTP_METHOD_PATCH, /*!< HTTP PATCH Method */
HTTP_METHOD_DELETE, /*!< HTTP DELETE Method */
HTTP_METHOD_HEAD, /*!< HTTP HEAD Method */
HTTP_METHOD_NOTIFY, /*!< HTTP NOTIFY Method */
HTTP_METHOD_SUBSCRIBE, /*!< HTTP SUBSCRIBE Method */
HTTP_METHOD_UNSUBSCRIBE,/*!< HTTP UNSUBSCRIBE Method */
HTTP_METHOD_OPTIONS, /*!< HTTP OPTIONS Method */
HTTP_METHOD_MAX,
} esp_http_client_method_t;
GET获取数据使用esp_http_client_perform函数
在使用其他方法或重新设置url使用函数:
esp_http_client_set_url(client, "http://httpbin.org/post");
esp_http_client_set_method(client, HTTP_METHOD_POST);
5、实例
static void vTaskHttpGet(void *pvParameters)
{
//等待连接成功,或已经连接有断开连接,此函数会一直阻塞,只有有连接
xEventGroupWaitBits(xCreatedEventGroup_WifiConnect,// 事件标志组句柄
WIFI_CONNECTED_BIT, // 等待bit0和bit1被设置
pdFALSE, //TRUE退出时bit0和bit1被清除,pdFALSE退出时bit0和bit1不清除
pdTRUE, //设置为pdTRUE表示等待bit1和bit0都被设置,pdFALSE表示等待bit1或bit0其中一个被设置
portMAX_DELAY); //等待延迟时间,一直等待
http_url_test();
http_hostname_path_test();
ESP_LOGI(TAG, "Finish http Test");
vTaskDelete(NULL);
}
在任务vTaskHttpGet中测试
static void http_url_test(void)
{
esp_http_client_config_t config = {
.url = "http://httpbin.org/get",
.event_handler = _http_event_handler,
};
//esp_http_client_config_t的参数分配内存,初始化数据,注册tcp的读写连接回调函数
esp_http_client_handle_t client = esp_http_client_init(&config);
// GET,默认方法
//发送接收数据
esp_err_t err = esp_http_client_perform(client);
if (err == ESP_OK) {
ESP_LOGI(TAG, "HTTP GET Status = %d, content_length = %d",
esp_http_client_get_status_code(client),
esp_http_client_get_content_length(client));
} else {
ESP_LOGE(TAG, "HTTP GET request failed: %s", esp_err_to_name(err));
}
// POST
const char *post_data = "field1=value1&field2=value2";
esp_http_client_set_url(client, "http://httpbin.org/post");
esp_http_client_set_method(client, HTTP_METHOD_POST);
esp_http_client_set_post_field(client, post_data, strlen(post_data));
err = esp_http_client_perform(client);
if (err == ESP_OK) {
ESP_LOGI(TAG, "HTTP POST Status = %d, content_length = %d",
esp_http_client_get_status_code(client),
esp_http_client_get_content_length(client));
} else {
ESP_LOGE(TAG, "HTTP POST request failed: %s", esp_err_to_name(err));
}
//PUT
esp_http_client_set_url(client, "http://httpbin.org/put");
esp_http_client_set_method(client, HTTP_METHOD_PUT);
err = esp_http_client_perform(client);
if (err == ESP_OK) {
ESP_LOGI(TAG, "HTTP PUT Status = %d, content_length = %d",
esp_http_client_get_status_code(client),
esp_http_client_get_content_length(client));
} else {
ESP_LOGE(TAG, "HTTP PUT request failed: %s", esp_err_to_name(err));
}
//PATCH
esp_http_client_set_url(client, "http://httpbin.org/patch");
esp_http_client_set_method(client, HTTP_METHOD_PATCH);
esp_http_client_set_post_field(client, NULL, 0);
err = esp_http_client_perform(client);
if (err == ESP_OK) {
ESP_LOGI(TAG, "HTTP PATCH Status = %d, content_length = %d",
esp_http_client_get_status_code(client),
esp_http_client_get_content_length(client));
} else {
ESP_LOGE(TAG, "HTTP PATCH request failed: %s", esp_err_to_name(err));
}
//DELETE
esp_http_client_set_url(client, "http://httpbin.org/delete");
esp_http_client_set_method(client, HTTP_METHOD_DELETE);
err = esp_http_client_perform(client);
if (err == ESP_OK) {
ESP_LOGI(TAG, "HTTP DELETE Status = %d, content_length = %d",
esp_http_client_get_status_code(client),
esp_http_client_get_content_length(client));
} else {
ESP_LOGE(TAG, "HTTP DELETE request failed: %s", esp_err_to_name(err));
}
//HEAD
esp_http_client_set_url(client, "http://httpbin.org/get");
esp_http_client_set_method(client, HTTP_METHOD_HEAD);
err = esp_http_client_perform(client);
if (err == ESP_OK) {
ESP_LOGI(TAG, "HTTP HEAD Status = %d, content_length = %d",
esp_http_client_get_status_code(client),
esp_http_client_get_content_length(client));
} else {
ESP_LOGE(TAG, "HTTP HEAD request failed: %s", esp_err_to_name(err));
}
//释放内存
esp_http_client_cleanup(client);
}
6、调试结果
所有文章源代码:https://download.csdn.net/download/lu330274924/88518092