ESP32-Web-Server 实战编程-使用文件系统建立强大的 web 系统

ESP32-Web-Server 实战编程-使用文件系统建立强大的 web 系统

概述

在前述章节我们讲述了在网页端控制多个 GPIO 的案例。当程序开始变得复杂,让一些功能“自动起来”是一个好的选择。

在前面的示例中,我们需要在后端为每个前端代码的 URL 指定一个对应的 handler,在 URL 变的越来越多的情况下,这种处理将变的不那么方便。

此外,随着系统功能越来越多,前端设计中使用的 HTML文件、CSS 文件、JS 文件越来越多,如果系统能自动管理、加载对应的文件,将对项目的设计与维护是很大的改善。

本节开始,我们将在后端代码中使用文件系统,默认使用 ESP-IDF 提供的 SPIFFS 文件系统,读者也可以使用更为通用的 Fatfs 文件系统,本质上两者是等价的。

需求及功能解析

功能还是上节讲述的在网页控制一个 LED 灯的亮灭。

本节演示如何通过文件系统来保存前端(HTML、CSS、JS 文件)所需要的内容,并在后端系统中需要指定的文件时实现自动索引到 SPIFFS 文件系统中对应的前端文件。

ESP32-Web-Server 实战编程-使用文件系统建立强大的 web 系统_第1张图片

示例解析

目录结构

├── CMakeLists.txt
├── main
│   ├── CMakeLists.txt
│   └── main.c                 User application
├── components
│   └── fs_image
		└── web_image
			└── index.html
			└── CSS
			└── JS
			└── CMakeLists.txt
└── README.md                  This is the file you are currently reading
  • 目录结构主要包含主目录 main,以及组件目录 components.

  • 其中组件目录components中包含了用于存储网页文件的 fs_image 目录(即前述前端文件),fs_image 目录下的 web_image 是文件系统中的内容。IDF 中通过 CMakeLists.txt 中指定的语句,将 web_image 中的内容,按照相同的目录结构写入到 ESP32 的 flash 存储器中:

    set(WEB_SRC_DIR "${CMAKE_CURRENT_SOURCE_DIR}/web_image")
    if (EXISTS ${WEB_SRC_DIR})
        spiffs_create_partition_image(fs ${WEB_SRC_DIR} FLASH_IN_PROJECT)
    else()
        message(FATAL_ERROR "${WEB_SRC_DIR} doesn't exit.")
    endif()
    

    ESP32-Web-Server 实战编程-使用文件系统建立强大的 web 系统_第2张图片

前端代码

前端代码与上节的内容一致,只是存储目录更加规范,HTML、CSS、JS 分别是不同的文件:
ESP32-Web-Server 实战编程-使用文件系统建立强大的 web 系统_第3张图片

此外,在 HTML 中对于需要的 CSS 文件、JS 文件,分别使用 hrefsrc 指定对应文件在文件系统中的存储位置:



后端代码

后端代码中主要是增加了文件系统的初始化,以及自动在文件系统中查找需要的文件的 handler。

1)增加文件系统的初始化:

/* Start the server for the first time */
ESP_ERROR_CHECK(init_fs());

2)在文件系统中增加查找文件的 handler:

httpd_uri_t httpd_uri_array[] = {
        {"/states", HTTP_GET, output_states_get_handler, rest_context},
        {"/update", HTTP_GET, update_state_get_handler, rest_context},
        {"/*", HTTP_GET, rest_common_get_handler,rest_context}//Catch-all callback function for the filesystem, this must be set to the array last one
    };

其中 “/states”、“/update” 分别是查询当前 GPIO 状态、更新 GPIO 状态的 ULR。

新增的 “/*” 是一个通配符,必须放在httpd_uri_array[] 的最后一个,代表上述所有未匹配到的 URL,都去这个通配符对应的 handler 里去查找对应的文件,获取对应的数据。这就是在文件系统中自动查找对应文件的关键处理函数。

当使用浏览器访问对应的 URL 时,会请求对应的文件,ESP32 将在 rest_common_get_handler() 中根据 URL 中指定的文件信息查找存储在 ESP32 SPIFFS 文件系统中的内容。

示例效果

ESP32-Web-Server 实战编程-使用文件系统建立强大的 web 系统_第4张图片

讨论

1)前端代码与后端代码是有对应关系的,本示例中前端发出的 URL 中通过 ? 识别请求的文件名称,因此后端代码中有:

char* p = strrchr(filepath, '?');
    if (p != NULL) {
        *p = '\0';
    }

int fd = open(filepath, O_RDONLY, 0);

2)不同的文件有不同的发送类型符号,本例中通过文件的后缀名,自动识别要打开的文件,并设置对应的文件类型描述符号:

/* Set HTTP response content type according to file extension */
static esp_err_t set_content_type_from_file(httpd_req_t* req, const char* filepath)
{
    const char* type = "text/plain";
    if (CHECK_FILE_EXTENSION(filepath, ".html")) {
        type = "text/html";
    } else if (CHECK_FILE_EXTENSION(filepath, ".js")) {
        type = "application/javascript";
    } else if (CHECK_FILE_EXTENSION(filepath, ".css")) {
        type = "text/css";
    } else if (CHECK_FILE_EXTENSION(filepath, ".png")) {
        type = "image/png";
    } else if (CHECK_FILE_EXTENSION(filepath, ".ico")) {
        type = "image/x-icon";
    } else if (CHECK_FILE_EXTENSION(filepath, ".svg")) {
        type = "text/xml";
    }
    return httpd_resp_set_type(req, type);
}

3)注意初始化 web 时,其文件系统的地址,要和实际使用的 spiffs mount 的 路径 web_base_point 要一致,否则会无法正确找到对应的文件:

server = start_webserver(web_base_point);
esp_err_t init_fs(void)
{
    esp_vfs_spiffs_conf_t conf = {
        .base_path = web_base_point,
        .partition_label = NULL,
        .max_files = 5,//maybe the num can be set smaller
        .format_if_mount_failed = false
    };
    ...
}

总结

1)本节主要是介绍通过文件系统保存 ESP32 Web 的前端文件,然后在后端代码中引入 SPIFFS 文件系统。

2)通过在后端代码中新增 “/*” 通配符,实现所有未匹配到的 URL,都自动地去这个通配符对应的 handler 里去查找对应的文件,获取对应的数据。

资源链接

1)ESP32-Web-Server ESP-IDF系列博客介绍
2)对应示例的 code 链接 (点击直达代码仓库)

3)下一篇:ESP32-Web-Server 实战编程- 使用 AJAX 自动更新网页内容

(码字不易感谢点赞或收藏)

你可能感兴趣的:(ESP-Web开发,物联网,服务器,web,嵌入式硬件,html)