ESP32系列四:搭建http的webserver的服务器

这篇具有很好参考价值的文章主要介绍了ESP32系列四:搭建http的webserver的服务器。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

最近在使用ESP32搭建web服务器测试,发现esp32搭建这类开发环境还是比较方便的。具体的http协议这里就不再赘述,我们主要说一下如何使用ESP32提供的API来搭建我们的http web。

一、web服务器搭建过程

1、配置web服务器

在ESP-IDF中,Web服务器使用httpd组件实现。我们需要先创建httpd_config_t结构体,指定服务器的端口、最大并发连接数、URI匹配处理器等选项。然后,我们通过调用httpd_start函数来启动Web服务器。(使用默认的配置就可以,包括端口号都已经默认配置好了)

httpd_config_t config = HTTPD_DEFAULT_CONFIG();
httpd_handle_t server = NULL;

// 设置服务器端口为80
config.server_port = 80;

// 创建HTTP服务器句柄
if (httpd_start(&server, &config) != ESP_OK) {
    printf("Error starting server!\n");
    return;
}

2、 注册 URI处理器
在Web服务器启动后,我们需要为不同的URI注册处理器函数。当Web服务器接收到请求时,会根据请求的URI选择相应的处理器函数进行处理。在ESP-IDF中,我们可以使用httpd_register_uri_handler函数注册URI处理器。该函数的原型如下

esp_err_t httpd_register_uri_handler(httpd_handle_t hd, const httpd_uri_t *uri)

其中,hd参数为HTTP服务器句柄;uri参数为包含URI路径、HTTP方法、处理函数等信息的结构体指针。例如:

static const httpd_uri_t echo = {
    .uri       = "/",
    .method    = HTTP_POST,
    .handler   = echo_post_handler,
    .user_ctx  = NULL
};
static esp_err_t echo_post_handler(httpd_req_t *req)
{
    char buf[100];
    // char ssid[10];
    // char pswd[10];
    int ret, remaining = req->content_len;

    while (remaining > 0) {
        /* Read the data for the request */
        if ((ret = httpd_req_recv(req, buf,
                        MIN(remaining, sizeof(buf)))) <= 0) {
            if (ret == HTTPD_SOCK_ERR_TIMEOUT) {
                /* Retry receiving if timeout occurred */
                continue;
            }
            return ESP_FAIL;
        }

        /* Send back the same data */
        httpd_resp_send_chunk(req, buf, ret);
        remaining -= ret;

        esp_err_t e = httpd_query_key_value(buf,"ssid",wifi_name,sizeof(wifi_name));
        if(e == ESP_OK) {
            printf("ssid = %s\r\n",wifi_name);
        }
        else {
            printf("error = %d\r\n",e);
        }

        e = httpd_query_key_value(buf,"password",wifi_password,sizeof(wifi_password));
        if(e == ESP_OK) {
            printf("pswd = %s\r\n",wifi_password);
        }
        else {
            printf("error = %d\r\n",e);
        }
        /* Log data received */
        ESP_LOGI(TAG, "=========== RECEIVED DATA ==========");
        ESP_LOGI(TAG, "%.*s", ret, buf);
        ESP_LOGI(TAG, "====================================");
    }

    // End response
    httpd_resp_send_chunk(req, NULL, 0);
    if(strcmp(wifi_name ,"\0")!=0 && strcmp(wifi_password,"\0")!=0)
    {
        xSemaphoreGive(ap_sem);
        ESP_LOGI(TAG, "set wifi name and password successfully! goto station mode");
    }
    return ESP_OK;
}

html的网页如下:这个网页包含了按钮的定义,以及发送json格式的数据。

最后送json数据的时候,要用JSON.stringify方法格式化data,否则esp32解析json会报错,此处一定要注意!!!
整体html界面非常简单,没有基础的也很容易读懂,里面写了一个js函数,该函数是在点击按钮的时候触发,功能主要是读取文本框输入的数据,将数据封装为json格式,然后post发送数据,xhttp.open(“POST”, “/wifi_data”, true);中的url “/wifi_data”和esp32服务端中的定义要一致,否则是无法成功的。

<!DOCTYPE html>
<head>
    <meta charset="utf-8">
    <title>Web server system</title>
</head>
<table class="fixed" border="5">
    <col width="1000px" /><col width="500px" />
    <tr><td>
        <h2 style=" text-align:center;"> **** Web Server ***</h2>


        <h3>wifi 密码配置</h3>
    <div>
        <label for="name">wifi名称</label>
        <input type="text" id="wifi" name="car_name" placeholder="ssid">
        <br>
        <label for="type">密码</label>
        <input type="text" id="code" name="car_type" placeholder="password">
        <br>
        <button id ="send_WIFI" type="button" onclick="send_wifi()">提交</button>
    </div>
    </td><td>
        <table border="10">
            <tr>
                <td>
                    <label for="newfile">Upload a file</label>
                </td>
                <td colspan="2">
                    <input id="newfile" type="file" onchange="setpath()" style="width:100%;">
                </td>
            </tr>
            <tr>
                <td>
                    <label for="filepath">Set path on server</label>
                </td>
                <td>
                    <input id="filepath" type="text" style="width:100%;">
                </td>
                <td>
                    <button id="upload" type="button" onclick="upload()">Upload</button>
                </td>
            </tr>
        </table>
    </td></tr>
</table>
<script>
function setpath() {
    var default_path = document.getElementById("newfile").files[0].name;
    document.getElementById("filepath").value = default_path;
}
function upload() {
    var filePath = document.getElementById("filepath").value;
    var upload_path = "/upload/" + filePath;
    var fileInput = document.getElementById("newfile").files;

    /* Max size of an individual file. Make sure this
     * value is same as that set in file_server.c */
    var MAX_FILE_SIZE = 200*1024;
    var MAX_FILE_SIZE_STR = "200KB";

    if (fileInput.length == 0) {
        alert("No file selected!");
    } else if (filePath.length == 0) {
        alert("File path on server is not set!");
    } else if (filePath.indexOf(' ') >= 0) {
        alert("File path on server cannot have spaces!");
    } else if (filePath[filePath.length-1] == '/') {
        alert("File name not specified after path!");
    } else if (fileInput[0].size > 200*1024) {
        alert("File size must be less than 200KB!");
    } else {
        document.getElementById("newfile").disabled = true;
        document.getElementById("filepath").disabled = true;
        document.getElementById("upload").disabled = true;

        var file = fileInput[0];
        var xhttp = new XMLHttpRequest();
        xhttp.onreadystatechange = function() {
            if (xhttp.readyState == 4) {
                if (xhttp.status == 200) {
                    document.open();
                    document.write(xhttp.responseText);
                    document.close();
                } else if (xhttp.status == 0) {
                    alert("Server closed the connection abruptly!");
                    location.reload()
                } else {
                    alert(xhttp.status + " Error!\n" + xhttp.responseText);
                    location.reload()
                }
            }
        };
        xhttp.open("POST", upload_path, true);
        xhttp.send(file);
    }
}

function send_wifi() {
    var input_ssid = document.getElementById("wifi").value;
    var input_code = document.getElementById("code").value;
    var xhttp = new XMLHttpRequest();
        xhttp.open("POST", "/wifi_data", true);
        xhttp.onreadystatechange = function() {
            if (xhttp.readyState == 4) {
                if (xhttp.status == 200) {
                    console.log(xhttp.responseText);
                } else if (xhttp.status == 0) {
                    alert("Server closed the connection abruptly!");
                    location.reload()
                } else {
                    alert(xhttp.status + " Error!\n" + xhttp.responseText);
                    location.reload()
                }
            }
        };
    var data = {
        "wifi_name":input_ssid,
        "wifi_code":input_code
    }
        xhttp.send(JSON.stringify(data));
}

</script>
static esp_err_t html_default_get_handler(httpd_req_t *req)
{
    // /* Send HTML file header */
    // httpd_resp_sendstr_chunk(req, "<!DOCTYPE html><html><body>");

    /* Get handle to embedded file upload script */
    extern const unsigned char upload_script_start[] asm("_binary_upload_script_html_start");
    extern const unsigned char upload_script_end[] asm("_binary_upload_script_html_end");
    const size_t upload_script_size = (upload_script_end - upload_script_start);

    /* Add file upload form and script which on execution sends a POST request to /upload */
    httpd_resp_send_chunk(req, (const char *)upload_script_start, upload_script_size);

    /* Send remaining chunk of HTML file to complete it */
    httpd_resp_sendstr_chunk(req, "</body></html>");

    /* Send empty chunk to signal HTTP response completion */
    httpd_resp_sendstr_chunk(req, NULL);
    return ESP_OK;
}

    httpd_uri_t html_default = {
        .uri = "/", // Match all URIs of type /path/to/file
        .method = HTTP_GET,
        .handler = html_default_get_handler,
        .user_ctx = "html" // Pass server data as context
    };

    httpd_register_uri_handler(server, &html_default);

这里要特别注意:

1)、.uri = "/",这个表示当你打开网页的IP地址后第一个要显示的页面,也就是要放到根目录下("/"也就是根目录)。

2)、ESP32可以直接将html的网页编译进来不需要转为数组,但在CMakeList.txt文件中需要EMBED_FILES upload_script.html样的形式引入网页文件。这个html编译出出来的文本文件怎么使用呢。wifi.html编译出来一般名称是默认的_binary_名称_类型_start。这个指针代编译出来文件的起始地址。_binary_名称_类型_end,代表结束地址。wifi.html的引用方式如下。通过以下的方式就可以获得html这个大数组。

    extern const unsigned char upload_script_start[] asm("_binary_upload_script_html_start");
    extern const unsigned char upload_script_end[] asm("_binary_upload_script_html_end");
    const size_t upload_script_size = (upload_script_end - upload_script_start);

    /* Add file upload form and script which on execution sends a POST request to /upload */
    httpd_resp_send_chunk(req, (const char *)upload_script_start, upload_script_size);

3、实现URI处理函数

在注册URI处理器后,我们需要实现对应的处理器函数。URI处理器函数的原型为:

typedef esp_err_t (*httpd_uri_func_t)(httpd_req_t *req);

如上面示例中的:

static esp_err_t html_default_get_handler(httpd_req_t *req)

4、处理HTTP请求
在URI处理器函数中,我们可以通过HTTP请求信息结构体指针httpd_req_t获取HTTP请求的各种参数和数据。以下是一些常用的HTTP请求处理函数:

httpd_req_get_hdr_value_str:获取HTTP请求头中指定字段的值(字符串格式)
httpd_req_get_url_query_str:获取HTTP请求URL中的查询参数(字符串格式)
httpd_query_key_value:解析HTTP请求URL中的查询参数,获取指定参数名的值(字符串格式)
httpd_req_recv:从HTTP请求接收数据
httpd_req_send:发送HTTP响应数据
httpd_resp_set_type:设置HTTP响应内容的MIME类型
httpd_resp_send_chunk:分块发送HTTP响应数据。
例如,以下是一个URI处理器函数的示例,用于处理/echo路径的POST请求:

static esp_err_t echo_post_handler(httpd_req_t *req)
{
    char buf[1024];
    int ret, remaining = req->content_len;

    // 从HTTP请求中接收数据
    while (remaining > 0) {
        ret = httpd_req_recv(req, buf, MIN(remaining, sizeof(buf)));
        if (ret <= 0) {
            if (ret == HTTPD_SOCK_ERR_TIMEOUT) {
                // 处理超时
                httpd_resp_send_408(req);
            }
            return ESP_FAIL;
        }

        // 处理接收到的数据
        // ...

        remaining -= ret;
    }

    // 发送HTTP响应
    httpd_resp_set_type(req, HTTPD_TYPE_TEXT);
    httpd_resp_send(req, "Received data: ", -1);
    httpd_resp_send_chunk(req, buf, req->content_len);
    httpd_resp_send_chunk(req, NULL, 0);

    return ESP_OK;
}

5、 发送响应
在URI处理函数中,可以使用httpd_resp_send()函数将响应发送回客户端。该函数需要传入一个httpd_req_t结构体作为参数,该结构体表示HTTP请求和响应。

例如,在上面的hello_get_handler处理函数中,可以使用httpd_resp_send()函数将“Hello, World!”字符串作为响应发送回客户端:

static esp_err_t hello_get_handler(httpd_req_t *req)
{
    const char* resp_str = "Hello, World!";
    httpd_resp_send(req, resp_str, strlen(resp_str));
    return ESP_OK;
}

二、主要使用API的说明
1. httpd_register_uri_handler
用于将HTTP请求的URI路由到处理程序。这个函数接收两个参数:httpd_handle_t类型的HTTP服务器句柄和httpd_uri_t类型的URI配置。

2. httpd_handle_t
httpd_handle_t是HTTP服务器的一个句柄,它是通过httpd_start函数创建的。而httpd_uri_t则定义了HTTP请求的URI信息,包括URI路径、HTTP请求方法和处理函数等。

3. httpd_query_key_value获取变量值
httpd_query_key_value 用于从查询字符串中获取指定键的值。查询字符串是指URL中?后面的部分,包含多个键值对,每个键值对之间使用&分隔。例如,对于以下URL:
http://192.168.1.1/path/to/handler?key1=value1&key2=value2
获取其中的:
esp_err_t httpd_query_key_value(const char *query, const char *key, char *buf, size_t buf_len);

这是一个使用示例

char query_str[] = "key1=value1&key2=value2";
char key[] = "key1";
char value[16];

if (httpd_query_key_value(query_str, key, value, sizeof(value)) == ESP_OK) {
    printf("value=%s\n", value);
} else {
    printf("key not found\n");
}

4. 获取get参数示例

下面定义的 handler 演示了如何从请求参数里解析 字符串param1和整型变量param2:

 esp_err_t index_handler(httpd_req_t *req)
{
     char* query_str = NULL;
     char param1_value[10] = {0};
     int param2_value=0;

     query_str = strstr(req->uri, "?");
     if(query_str!=NULL){
         query_str ++;
         httpd_query_key_value(query_str, "param1", param1_value, sizeof(param1_value));
         char param2_str[10] = {0};
         httpd_query_key_value(query_str, "param2", param2_str, sizeof(param2_str));
         param2_value = atoi(param2_str);
     }

     char resp_str[50] = {0};
     snprintf(resp_str, sizeof(resp_str), "param1=%s, param2=%d", param1_value, param2_value);
    httpd_resp_send(req, resp_str, strlen(resp_str));
    return ESP_OK;
}

5. 获取post参数示例

下面的示例代码中根据httpd_req_t的content_len来分配一个缓冲区,并解析请求中的POST参数:文章来源地址https://www.toymoban.com/news/detail-841965.html


 esp_err_t post_demo_handler(httpd_req_t *req)
{
    char post_string[64];
    int post_int=0;

    if (req->content_len > 0)
    {
        // 从请求体中读取POST参数
        char *buf = malloc(req->content_len + 1);
        int ret = httpd_req_recv(req, buf, req->content_len);
        if (ret <= 0)
        {
            // 接收数据出错
            free(buf);
            return ESP_FAIL;
        }
        buf[req->content_len] = '\0';

        // 解析POST参数
        char *param_str;
        param_str = strtok(buf, "&");
        while (param_str != NULL)
        {
            char *value_str = strchr(param_str, '=');
            if (value_str != NULL)
            {
                *value_str++ = '\0';
                if (strcmp(param_str, "post_string") == 0)
                {
                    strncpy(post_string, value_str, sizeof(post_string));
                }
                else if (strcmp(param_str, "post_int") == 0)
                {
                    post_int = atoi(value_str);
                }
            }
            param_str = strtok(NULL, "&");
        }

        free(buf);
    }

    // 将结果打印输出
    printf("post_string=%s, post_int=%d\n", post_string, post_int);

    // 返回成功
    httpd_resp_send(req, NULL, 0);
    return ESP_OK;
}


 httpd_uri_t post_uri = {
         .uri = "/post",
         .method = HTTP_POST,
         .handler = post_demo_handler,
         .user_ctx = NULL
 };

到了这里,关于ESP32系列四:搭建http的webserver的服务器的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 基于ESP32搭建物联网服务器十二(使用MQTT协议与ESP32互动)

    在之前的文章中:基于ESP32搭建物联网服务器十一(用WEB页面控制引脚(GPIO)功能)_esp32webserver 控制io_你的幻境的博客-CSDN博客 已经简单地介绍了MQTT协议,对比于其它网络协议,MQTT协议在物联网的开发中,它的特点使它适用于大多数受限的环境。例如网络代价昂贵,带宽低、不可

    2024年02月02日
    浏览(50)
  • 基于ESP32搭建物联网服务器一(AP配网)

    目录 一、WiFi.mode();设置配网模式 二、WiFi.softAP();设置ESP32的WIFI属性 三、WiFi.softAPConfig();设置ESP32的IP,网关,子网掩码,DHCP    ESP32的AP配网模式可以通过无线WIFI连接的方式来连接来控制ESP32或获取ESP32的数据。 设置ESP32的AP配网需要的库为 WiFi.h 默认情况下,arduino IDE安装好

    2024年02月13日
    浏览(55)
  • 【ESP8266 快速入门】示例5:Arduino环境实现OTA无线升级固件功能WebServer网页服务器方式

    使用【ESP8266】Arduino环境实现OTA无线升级固件功能,由LED闪烁程序通过OTA升级为PWM呼吸灯程序。 OTA听起来挺牛的一个功能,其全称为(Over-The-Air),直译为空中传送。就是通过无线方式实现固件升级。 对于实际封装好的项目,ESP8266已经包装好了,不方便使用数据线来下载程

    2024年02月03日
    浏览(46)
  • ESP32-HTTP_webServer库(Arduino)

    ESP32 是一款功能强大的微控制器,具有丰富的网络和通信功能。其中之一就是支持 HTTP 协议,这使得 ESP32 可以用于创建 Web 服务器。 HTTP是什么? HTTP (Hyper Text Transfer Protocol),即超文本传输协议,是一种无状态的、建立在 TCP 之上的连接。其基本的工作流程是:客户端发送

    2024年01月21日
    浏览(39)
  • 提供最全面最详细的ESP32从零开始搭建一个物联网平台教程(从最基本的配网和内建WEB服务器开始到自已搭建一个MQTT服务器)

    目录 教程大纲  硬件需求 教程说明 教程章节链接 ESP32搭建WEB服务器一(AP配网) ESP32搭建WEB服务器二(STA模式) ESP32搭建WEB服务器三(AP模式与STA模式共存) ESP32搭建WEB服务器四(最简单的WEB服务器) ESP32搭建WEB服务器五(内嵌HTML) ESP32搭建WEB服务器六(利用SPIFFS存放html,css,js等文件(读取

    2024年02月13日
    浏览(65)
  • 基于ESP32搭建物联网服务器六(利用SPIFFS存放html,css,js等文件(读取html)

    在前文中:ESP32的web服务器(内嵌HTML)_你的幻境的博客-CSDN博客 已经实现建立了一个WEB服务器了,但是页面的HTML代码是镶嵌在C语言代码中的,大部份情况下,不管是调试或者使用都是很不方便的。但是ESP32的SPIFFS提供了很好的解决方法,SPIFFS相当于ESP32中的一个硬盘分区,每种版

    2024年02月02日
    浏览(60)
  • 从零开始用Nodejs搭建一个MQTT服务器,并且用stm32通过esp8266进行消息订阅和发布

    最近在做一个物联网项目,需要用到服务器进行数据的存储和数据的请求和发送,之前我用过onenet平台上的http服务,虽然能通过get和post请求进行数据的提交和发送,但是平台上的数据发生改变却不能主动推送给esp8266,与我此次的项目不符合,所以pass。然后我了解了下mqtt协

    2024年02月04日
    浏览(52)
  • Android-音视频学习系列-(八)基于-Nginx-搭建(rtmp、http)直播服务器

    #!/bin/sh HTTP_FLV_MODULE_PATH=…/nginx-http-flv-module-1.2.7 OpenSSL_PATH=…/openssl-1.1.1d #–prefix=./bin 代表编译完成之后输出的路径地址 #–add-module 将拓展模块添加到当前一起编译 ./configure --prefix=./bin –add-module= H T T P F L V M O D U L E P A T H   − − w i t h − o p e n s s l = HTTP_FLV_MODULE_PATH --with

    2024年04月15日
    浏览(64)
  • ESP32连接云服务器【WebSocket】

    🔮🔮🔮🔮🔮相关文章🔮🔮🔮🔮🔮 ESP32连接MQ Sensor实现气味反应 🔗 https://blog.csdn.net/ws15168689087/article/details/131365573 ESP32+MQTT+MySQL实现发布订阅【气味数据收集】 🔗 https://blog.csdn.net/ws15168689087/article/details/131627595 个人云服务器搭建MQTT服务器 🔗 https://blog.csdn.net/ws15168689

    2024年02月16日
    浏览(50)
  • 基于ESP32的简易web服务器

    本文介绍一下如何使用ESP32快速方便的搭建一个简易的web服务器。 使用ESP32或ESP8266搭建web服务器的方式有很多,但是大多数都的web页面代码都是内嵌在程序中的,这样如果要修改web页面就十分的不方便。今天介绍一种方法将web页面的代码以文件的形式上传到存储器中,然后在

    2024年02月09日
    浏览(53)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包