京东6.18大促主会场领京享红包更优惠

 找回密码
 立即注册

QQ登录

只需一步,快速开始

怎样搭建http的webserver服务器

2024-11-3 15:08| 发布者: 8b79| 查看: 108| 评论: 0

摘要: 目录一、web服务器搭建过程1、配置web服务器2、 注册 URI处理器3、实现URI处理函数4、处理HTTP哀求5、 发送相应二、紧张使用API的说明近来在使用ESP32搭建web服务器测试,发现esp32搭建这类开发环境照旧比较方便的。
目录

近来在使用ESP32搭建web服务器测试,发现esp32搭建这类开发环境照旧比较方便的。具体的http协议这里就不再赘述,我们紧张说一下怎样使用ESP32提供的API来搭建我们的http web。

一、web服务器搭建过程

1、配置web服务器

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

[code]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; } [/code]

2、 注册 URI处理器

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

[code]esp_err_t httpd_register_uri_handler(httpd_handle_t hd, const httpd_uri_t *uri)[/code]

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

[code]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; }[/code]

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

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

[code]<!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>[/code] [code]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);[/code]

这里要特殊留意:

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

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

[code] 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);[/code]

3、实现URI处理函数

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

[code]typedef esp_err_t (*httpd_uri_func_t)(httpd_req_t *req); [/code]

如上面示例中的:

[code]static esp_err_t html_default_get_handler(httpd_req_t *req)[/code]

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哀求:

[code]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; } [/code]

5、 发送相应

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

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

[code]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; }[/code]

二、紧张使用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);

这是一个使用示例

[code]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"); } [/code]

4. 获取get参数示例

下面定义的 handler 演示了怎样从哀求参数里剖析 字符串param1和整型变量param2:

[code] 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; }[/code]

5. 获取post参数示例

下面的示例代码中根据httpd_req_t的content_len来分配一个缓冲区,并剖析哀求中的POST参数:

[code] 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 };[/code]

到此这篇关于搭建http的webserver的服务器的文章就介绍到这了,更多相关http的webserver服务器内容请搜刮脚本之家从前的文章或继承欣赏下面的相关文章希望各人以后多多支持脚本之家!


来源:https://www.jb51.net/server/326369fwu.htm
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
关闭

站长推荐上一条 /6 下一条

QQ|手机版|小黑屋|梦想之都-俊月星空 ( 粤ICP备18056059号 )|网站地图

GMT+8, 2025-7-1 18:11 , Processed in 0.044380 second(s), 18 queries .

Powered by Mxzdjyxk! X3.5

© 2001-2025 Discuz! Team.

返回顶部