乐鑫ESP32 https post请求

项目中遇到关于https的应用,例程中只有关于https的get,没有post,原以为只需要简单改动一下就能使用,但是实际调试过程中,发现不能用。 现在记录一下,防止忘记。
原例程是参照https_request_example_main.c文件中

https get

void app_main(void)
{
    ESP_ERROR_CHECK( nvs_flash_init() );
    ESP_ERROR_CHECK(esp_netif_init());
    ESP_ERROR_CHECK(esp_event_loop_create_default());

    /* This helper function configures Wi-Fi or Ethernet, as selected in menuconfig.
     * Read "Establishing Wi-Fi or Ethernet Connection" section in
     * examples/protocols/README.md for more information about this function.
     */
    ESP_ERROR_CHECK(example_connect());

    xTaskCreate(&https_get_task, "https_get_task", 8192, NULL, 5, NULL);
}

这个是主函数。其中的
ESP_ERROR_CHECK( nvs_flash_init() );
ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK(esp_event_loop_create_default());
ESP_ERROR_CHECK(example_connect());
分别做了flash初始化,网络初始化,回调事件创建,以及网络连接。
如果已经建立了网络连接可以只调用ESP_ERROR_CHECK(esp_event_loop_create_default());
xTaskCreate(&https_get_task, “https_get_task”, 8192, NULL, 5, NULL);
这两个,就可以直接进行https的相关操作。

static void https_get_task(void *pvParameters)
{
    char buf[512];
    int ret, len;

    while(1) {
        esp_tls_cfg_t cfg = {
            .crt_bundle_attach = esp_crt_bundle_attach,
        };

        struct esp_tls *tls = esp_tls_conn_http_new(WEB_URL, &cfg);

        if(tls != NULL) {
            ESP_LOGI(TAG, "Connection established...");
        } else {
            ESP_LOGE(TAG, "Connection failed...");
            goto exit;
        }

        size_t written_bytes = 0;
        do {
            ret = esp_tls_conn_write(tls,
                                     REQUEST + written_bytes,
                                     strlen(REQUEST) - written_bytes);
            if (ret >= 0) {
                ESP_LOGI(TAG, "%d bytes written", ret);
                written_bytes += ret;
            } else if (ret != ESP_TLS_ERR_SSL_WANT_READ  && ret != ESP_TLS_ERR_SSL_WANT_WRITE) {
                ESP_LOGE(TAG, "esp_tls_conn_write  returned 0x%x", ret);
                goto exit;
            }
        } while(written_bytes < strlen(REQUEST));

        ESP_LOGI(TAG, "Reading HTTP response...");

        do
        {
            len = sizeof(buf) - 1;
            bzero(buf, sizeof(buf));
            ret = esp_tls_conn_read(tls, (char *)buf, len);

            if(ret == ESP_TLS_ERR_SSL_WANT_WRITE  || ret == ESP_TLS_ERR_SSL_WANT_READ)
                continue;

            if(ret < 0)
           {
                ESP_LOGE(TAG, "esp_tls_conn_read  returned -0x%x", -ret);
                break;
            }

            if(ret == 0)
            {
                ESP_LOGI(TAG, "connection closed");
                break;
            }

            len = ret;
            ESP_LOGD(TAG, "%d bytes read", len);
            /* Print response directly to stdout as it is read */
            for(int i = 0; i < len; i++) {
                putchar(buf[i]);
            }
        } while(1);

    exit:
        esp_tls_conn_delete(tls);
        putchar('\n'); // JSON output doesn't have a newline at end

        static int request_count;
        ESP_LOGI(TAG, "Completed %d requests", ++request_count);

        for(int countdown = 10; countdown >= 0; countdown--) {
            ESP_LOGI(TAG, "%d...", countdown);
            vTaskDelay(1000 / portTICK_PERIOD_MS);
        }
        ESP_LOGI(TAG, "Starting again!");
    }
}
https_get_task()函数中,esp_tls_conn_http_new()是通过url建立https的连接。esp_tls_conn_write()完成传输,即通过TCP协议层传输https的header

http的协议格式
例程中的协议头是这样的。

static const char *REQUEST = "GET " WEB_URL " HTTP/1.0\r\n"
    "Host: "WEB_SERVER"\r\n"
    "User-Agent: esp-idf/1.0 esp32\r\n"
    "\r\n";

这里的WEB_SERVER,WEB_URL是用define定义的。(有一点需要注意的是,这种定义方式在Visual Studio中的C/C++会报错。)
下面的ret = esp_tls_conn_write(tls,
REQUEST + written_bytes,
strlen(REQUEST) - written_bytes);
是循环将header传输到对应的服务器上。
写完以后,开始等待http的回复。
后面进行回复读取:
bzero(buf, sizeof(buf));
ret = esp_tls_conn_read(tls, (char *)buf, len);
bzero()类似于memset(),不过在http当中用的比较多。

https post

但是上面的例程是进行https get请求的,若进行post请求呢?
大多数情况下,post请求都是需要上传参数的。不管是text,xml,还是json。
body应该怎么填的?一开始我是这样做的。

const char *REQUEST = "POST " WEB_URL " HTTP/1.0\r\n"
                            "Host: " WEB_SERVER "\r\n"
                            "User-Agent: Mozilla/5.0\r\n"
                            "Content-Type:application/json\r\n"
                            "Accept-Encoding: gzip, deflate\r\n"
                            "Connection:keep-alive\r\n"
                            "Content-Length:360\r\n"
                            "Accept:*/*\r\n"
                            "\r\n";
                            "{\r\n	\"appId\":	\"intelligent_cabinet\",\r\n	\"requestId\":	\"01831016-b18c-4a1e-a571\",\r\n	\"version\":	\"2.0\",\r\n	\"timestamp\":	\"1617325383000\",\r\n	\"sign\":	\"ZDJlNGJmZDQ4Y2MyOWNmOTU1ZDcyNTRkNzc3NDQwMzQwNzU1MGY2MQ==\"\r\n}";

格式是按照http的格式填充的,实际测试当中,发现body请求体并没有传到服务器。
后问了乐鑫的FAE,提示可以参考esp_http_client_example.c例程测试。
但是该例程当中也有不少的坑。
首先,这个例程当中包含多个请求方式,并且相当杂乱。

static void http_test_task(void *pvParameters)
{
    http_rest_with_url();
    http_rest_with_hostname_path();
#if CONFIG_ESP_HTTP_CLIENT_ENABLE_BASIC_AUTH
    http_auth_basic();
    http_auth_basic_redirect();
#endif
    http_auth_digest();
    http_relative_redirect();
    http_absolute_redirect();
    https_with_url();
    https_with_hostname_path();
    http_redirect_to_https();
    http_download_chunk();
    http_perform_as_stream_reader();
    https_async();
    https_with_invalid_url();
    http_native_request();

    ESP_LOGI(TAG, "Finish http example");
    vTaskDelete(NULL);
}

开始使用这个https_with_url();设置了一下,发现用不了,后面又调整了几次,终于发送成功了。
改的例程如下:

void https_with_url(void)
{
    char *outJson=NULL;
    char output_buffer[MAX_HTTP_OUTPUT_BUFFER] = {0};
    char request[512]={'\0'};
    outJson=rebuild_json();
    sprintf(request,"%s",outJson);
    free(outJson);
    esp_netif_init();
    esp_event_loop_create_default();
    esp_http_client_config_t config = {
        .url ="https://daily-robot.ele.me/bdi.robot_scheduler/v2/openapi/cater/order/prepared",
        .event_handler = http_event_handler,
    };
    esp_http_client_handle_t client = esp_http_client_init(&config);
    esp_http_client_set_method(client, HTTP_METHOD_POST);
    esp_http_client_set_header(client, "Content-Type", "application/json");
    esp_err_t err = esp_http_client_open(client, strlen(request));
    printf("https_with_url request =%s\n",request);
    if (err != ESP_OK) {
        ESP_LOGE(TAG, "Failed to open HTTP connection: %s", esp_err_to_name(err));
    } else {

        int wlen = esp_http_client_write(client, request, strlen(request));

        if (wlen < 0) {
            ESP_LOGE(TAG, "Write failed");
        }
        esp_err_t err = esp_http_client_perform(client);

        if (err == ESP_OK) {
            ESP_LOGI(TAG, "HTTPS Status = %d, content_length = %d",
                esp_http_client_get_status_code(client),
                esp_http_client_get_content_length(client));
        } else {
        ESP_LOGE(TAG, "Error perform http request %s", esp_err_to_name(err));
        }
    }
    esp_http_client_cleanup(client);
}

http回复的可以在http_event_handler()函数中的
case HTTP_EVENT_ON_DATA:
后面打印一下:

case HTTP_EVENT_ON_DATA:
            ESP_LOGD(TAG, "HTTP_EVENT_ON_DATA, len=%d", evt->data_len);
            /*
             *  Check for chunked encoding is added as the URL for chunked encoding used in this example returns binary data.
             *  However, event handler can also be used in case chunked encoding is used.
             */
            if (!esp_http_client_is_chunked_response(evt->client)) {
                // If user_data buffer is configured, copy the response into the buffer
                if (evt->user_data) {
                    memcpy(evt->user_data + output_len, evt->data, evt->data_len);
                } else {
                    if (output_buffer == NULL) {
                        output_buffer = (char *) malloc(esp_http_client_get_content_length(evt->client));
                        output_len = 0;
                        if (output_buffer == NULL) {
                            ESP_LOGE(TAG, "Failed to allocate memory for output buffer");
                            return ESP_FAIL;
                        }
                    }
                    memcpy(output_buffer + output_len, evt->data, evt->data_len);
                }
                output_len += evt->data_len;
            }
            printf("output_buffer=%s\n",output_buffer);
            break;

可以看收到了回复信息
postman测试回复

跟postman上面的测试结果一致,后面就可以添加自己的数据处理拉,完成。
源码在这里:乐鑫ESP32 http post请求源码修改

  • 9
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 13
    评论
2022 / 01/ 30: 新版esptool 刷micropython固件指令不是 esptool.py cmd... 而是 esptool cmd... 即可;另外rshell 在 >= python 3.10 的时候出错解决方法可以查看:  已于2022年发布的: 第二章:修复rshell在python3.10出错 免费内容: https://edu.csdn.net/course/detail/29666 micropython语法和python3一样,编写起来非常方便。如果你快速入门单片机玩物联网而且像轻松实现各种功能,那绝力推荐使用micropython。方便易懂易学。 同时如果你懂C语音,也可以用C写好函数并编译进micropython固件里然后进入micropython调用(非必须)。 能通过WIFI联网(2.1章),也能通过sim卡使用2G/3G/4G/5G联网(4.5章)。 为实现语音控制,本教程会教大家使用tensorflow利用神经网络训练自己的语音模型并应用。为实现通过网页控制,本教程会教大家linux(debian10 nginx->uwsgi->python3->postgresql)网站前后台入门。为记录单片机传输过来的数据, 本教程会教大家入门数据库。  本教程会通过通俗易懂的比喻来讲解各种原理与思路,并手把手编写程序来实现各项功能。 本教程micropython版本是 2019年6月发布的1.11; 更多内容请看视频列表。  学习这门课程之前你需要至少掌握: 1: python3基础(变量, 循环, 函数, 常用库, 常用方法)。 本视频使用到的零件与淘宝上大致价格:     1: 超声波传感器(3)     2: MAX9814麦克风放大模块(8)     3: DHT22(15)     4: LED(0.1)     5: 8路5V低电平触发继电器(12)     6: HX1838红外接收模块(2)     7:红外发射管(0.1),HX1838红外接收板(1)     other: 电表, 排线, 面包板(2)*2,ESP32(28)  
ESP32中的POST请求可以通过引入urequests模块并使用该模块中的post函数来实现。首先,需要导入urequests模块,以获取执行HTTP POST请求所需的函数。通过import urequests来引入该模块。然后,使用post函数来发送POST请求并传递相应的参数。具体的代码实现可以参考乐鑫ESP32HTTP POST请求源码修改。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [ESP8266之HTTP请求](https://download.csdn.net/download/weixin_38638002/14031809)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [乐鑫ESP32 https post请求](https://blog.csdn.net/weixin_44244400/article/details/115551627)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [ESP32 MicroPython:HTTP POST请求HTTP GET请求](https://blog.csdn.net/zhazhawoaini/article/details/107007818)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

蒙蒂锅巴

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值