当前位置: 首页 > news >正文

ESP32开发入门(九):HTTP服务器开发实践

一、HTTP服务器基础

1.1 什么是HTTP服务器?

HTTP服务器是能够处理HTTP请求并返回响应的网络服务程序。在物联网应用中,ESP32可以作为轻量级HTTP服务器,直接接收来自客户端(如浏览器、手机APP)的请求。

1.2 ESP32作为HTTP服务器的特点

  1. 轻量级:适合资源有限的嵌入式设备

  2. 低功耗:可作为电池供电设备的控制接口

  3. 本地网络服务:无需云端即可提供Web服务

  4. 实时交互:直接控制硬件设备

  5. 配置简单:无需复杂网络配置

1.3 典型应用场景

  1. 设备控制面板:通过网页控制LED、继电器等

  2. 传感器数据展示:实时显示温湿度等数据

  3. 设备配置界面:WiFi配置、参数设置

  4. OTA升级服务:本地固件更新

  5. 局域网IoT中心:聚合多个设备数据

二、ESP32-S3 HTTP服务器实现 (FreeRTOS + Arduino框架)

#include <WiFi.h>
#include <WebServer.h>
#include <ArduinoJson.h>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
​
// WiFi配置
const char* ssid = "Your_WiFi_SSID";
const char* password = "Your_WiFi_Password";
​
// 创建WebServer实例,监听80端口
WebServer server(80);
​
// FreeRTOS任务句柄
TaskHandle_t webServerTaskHandle = NULL;
​
// 传感器数据示例
float temperature = 25.0;
float humidity = 60.0;
​
// 处理根路径请求
void handleRoot() {String html = "<!DOCTYPE html><html><head>";html += "<title>ESP32 Web Server</title>";html += "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">";html += "<style>body{font-family:Arial;text-align:center;margin-top:50px;}";html += ".card{display:inline-block;width:150px;border-radius:10px;";html += "box-shadow:0 4px 8px 0 rgba(0,0,0,0.2);padding:20px;margin:10px;}";html += ".button{padding:10px 20px;background-color:#4CAF50;color:white;";html += "border:none;border-radius:5px;text-decoration:none;}</style></head>";html += "<body><h1>ESP32 Web Server</h1>";// 显示传感器数据html += "<div class=\"card\"><h3>Temperature</h3><p>" + String(temperature) + " °C</p></div>";html += "<div class=\"card\"><h3>Humidity</h3><p>" + String(humidity) + " %</p></div>";// 控制按钮html += "<div style=\"margin-top:30px;\">";html += "<a href=\"/led_on\" class=\"button\">LED ON</a> ";html += "<a href=\"/led_off\" class=\"button\">LED OFF</a>";html += "</div></body></html>";server.send(200, "text/html", html);
}
​
// 处理LED控制请求
void handleLEDOn() {digitalWrite(LED_BUILTIN, HIGH);server.send(200, "text/plain", "LED is ON");
}
​
void handleLEDOff() {digitalWrite(LED_BUILTIN, LOW);server.send(200, "text/plain", "LED is OFF");
}
​
// 处理API数据请求
void handleAPI() {StaticJsonDocument<200> jsonDoc;jsonDoc["device"] = "ESP32-S3";jsonDoc["temperature"] = temperature;jsonDoc["humidity"] = humidity;jsonDoc["uptime"] = millis() / 1000;String response;serializeJson(jsonDoc, response);server.send(200, "application/json", response);
}
​
// 处理未找到的路径
void handleNotFound() {String message = "File Not Found\n\n";message += "URI: ";message += server.uri();message += "\nMethod: ";message += (server.method() == HTTP_GET) ? "GET" : "POST";message += "\nArguments: ";message += server.args();message += "\n";for (uint8_t i = 0; i < server.args(); i++) {message += " " + server.argName(i) + ": " + server.arg(i) + "\n";}server.send(404, "text/plain", message);
}
​
// Web服务器任务
void webServerTask(void *pvParameters) {while (1) {server.handleClient();vTaskDelay(10 / portTICK_PERIOD_MS);}
}
​
void setup() {Serial.begin(115200);pinMode(LED_BUILTIN, OUTPUT);// 连接WiFiWiFi.begin(ssid, password);while (WiFi.status() != WL_CONNECTED) {delay(500);Serial.print(".");}Serial.println("");Serial.println("WiFi connected");Serial.print("IP address: ");Serial.println(WiFi.localIP());// 配置路由server.on("/", handleRoot);server.on("/led_on", handleLEDOn);server.on("/led_off", handleLEDOff);server.on("/api", handleAPI);server.onNotFound(handleNotFound);// 启动Web服务器server.begin();Serial.println("HTTP server started");// 创建Web服务器任务xTaskCreatePinnedToCore(webServerTask,      // 任务函数"WebServer Task",   // 任务名称8192,               // 堆栈大小NULL,               // 参数1,                  // 优先级&webServerTaskHandle, // 任务句柄1                   // 运行在核心1上);
}
​
void loop() {// 模拟更新传感器数据temperature = 25.0 + (millis() % 200) * 0.1;humidity = 60.0 + (millis() % 150) * 0.1;vTaskDelay(10000 / portTICK_PERIOD_MS); // 每10秒更新一次
}

2.1 代码说明

  1. WebServer初始化

    • 使用WebServer类创建服务器实例

    • 默认监听80端口(HTTP标准端口)

  2. 路由处理

    • server.on()注册路径处理函数

    • 支持静态页面和API接口

    • 处理GET/POST请求

  3. HTML生成

    • 动态生成响应页面

    • 包含CSS内联样式

    • 响应式设计适配移动设备

  4. JSON API

    • 使用ArduinoJson库生成JSON数据

    • 返回设备状态和传感器数据

  5. 多任务处理

    • 使用FreeRTOS单独处理Web请求

    • 避免阻塞主循环

2.2 使用说明

  1. 修改WiFi配置(ssidpassword)

  2. 根据需求添加更多路由处理

  3. 集成实际传感器读取代码

  4. 如需HTTPS支持需额外配置

2.3 所需库

  • WiFi.h (Arduino ESP32核心自带)

  • WebServer.h (Arduino ESP32核心自带)

  • ArduinoJson.h (需单独安装)

三、功能验证与测试

3.1 基础功能测试

  1. 上传代码后,查看串口输出的IP地址

  2. 在浏览器中输入http://[ESP32-IP]

  3. 应显示包含传感器数据和控制按钮的页面

  4. 点击LED控制按钮测试功能

  5. 访问http://[ESP32-IP]/api测试JSON API

3.2 高级测试场景

3.2.1 使用cURL测试API
# 获取设备信息
curl http://[ESP32-IP]/api
​
# 控制LED
curl http://[ESP32-IP]/led_on
curl http://[ESP32-IP]/led_off
3.2.2 POST请求测试

添加表单处理路由:

void handleForm() {if (server.method() != HTTP_POST) {server.send(405, "text/plain", "Method Not Allowed");return;}String message = "Received:\n";for (uint8_t i = 0; i < server.args(); i++) {message += server.argName(i) + ": " + server.arg(i) + "\n";}server.send(200, "text/plain", message);
}
​
// 在setup()中添加
server.on("/submit", HTTP_POST, handleForm);

测试命令:

curl -X POST -d "name=ESP32&value=100" http://[ESP32-IP]/submit

四、实际项目应用

4.1 智能家居控制面板

// 控制多个设备的HTML页面
void handleControlPanel() {String html = "<html><body><h1>Home Control</h1>";html += "<form action='/control' method='post'>";html += "Light: <input type='radio' name='light' value='1'>ON ";html += "<input type='radio' name='light' value='0' checked>OFF<br>";html += "Fan Speed: <input type='range' name='fan' min='0' max='3'><br>";html += "<input type='submit' value='Apply'>";html += "</form></body></html>";server.send(200, "text/html", html);
}
​
// 处理控制请求
void handleControl() {if (server.hasArg("light")) {int lightState = server.arg("light").toInt();digitalWrite(LIGHT_PIN, lightState);}if (server.hasArg("fan")) {int fanSpeed = server.arg("fan").toInt();analogWrite(FAN_PIN, fanSpeed * 85);}server.send(200, "text/plain", "Settings applied");
}

4.2 OTA升级服务

#include <Update.h>
​
void handleOTAUpdate() {server.sendHeader("Connection", "close");server.send(200, "text/html", "<form method='POST' action='/do_update' enctype='multipart/form-data'>""<input type='file' name='update'>""<input type='submit' value='Update'>""</form>");
}
​
void handleDoUpdate() {HTTPUpload& upload = server.upload();if (upload.status == UPLOAD_FILE_START) {Serial.printf("Update: %s\n", upload.filename.c_str());if (!Update.begin(UPDATE_SIZE_UNKNOWN)) {Update.printError(Serial);}} else if (upload.status == UPLOAD_FILE_WRITE) {if (Update.write(upload.buf, upload.currentSize) != upload.currentSize) {Update.printError(Serial);}} else if (upload.status == UPLOAD_FILE_END) {if (Update.end(true)) {Serial.printf("Update Success: %u\nRebooting...\n", upload.totalSize);server.sendHeader("Location", "/");server.send(303);} else {Update.printError(Serial);}}
}
​
// 在setup()中添加
server.on("/update", handleOTAUpdate);
server.on("/do_update", HTTP_POST, []() {server.send(200, "text/plain", (Update.hasError()) ? "FAIL" : "OK");ESP.restart();
}, handleDoUpdate);

五、性能优化与安全

5.1 性能优化技巧

  1. 使用SPIFFS存储静态文件

    #include <SPIFFS.h>
    ​
    void setup() {if(!SPIFFS.begin(true)){Serial.println("SPIFFS Mount Failed");return;}server.serveStatic("/", SPIFFS, "/index.html");
    }

  2. 启用Gzip压缩

    server.enableCORS(true);
    server.enableGzip();
  3. 连接复用

    server.setReusePort(true);

5.2 安全增强措施

  1. 基本认证

    server.requireAuthentication("admin", "password");
  2. HTTPS支持

    #include <HTTPSServer.hpp>
    using namespace httpsserver;
    ​
    // 需要加载证书和私钥
    HTTPSServer secureServer = HTTPSServer(443);
  3. 请求限制

    void handleRequest() {static unsigned long lastRequest = 0;if (millis() - lastRequest < 1000) {server.send(429, "text/plain", "Too Many Requests");return;}lastRequest = millis();// 正常处理
    }

六、扩展功能

6.1 WebSocket实时通信

#include <WebSocketsServer.h>
​
WebSocketsServer webSocket = WebSocketsServer(81);
​
void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t length) {switch(type) {case WStype_DISCONNECTED:Serial.printf("[%u] Disconnected!\n", num);break;case WStype_CONNECTED:Serial.printf("[%u] Connected!\n", num);break;case WStype_TEXT:Serial.printf("[%u] Received: %s\n", num, payload);webSocket.broadcastTXT(payload, length);break;}
}
​
void setup() {webSocket.begin();webSocket.onEvent(webSocketEvent);
}

6.2 mDNS服务发现

#include <ESPmDNS.h>
​
void setup() {if (MDNS.begin("esp32")) {Serial.println("mDNS responder started");MDNS.addService("http", "tcp", 80);}
}

七、总结与扩展学习

7.1 学习路径

  1. 进阶Web开发

    • 学习使用SPIFFS文件系统

    • 实现更复杂的前端界面

    • 添加WebSocket实时通信

  2. 安全增强

    • 实现HTTPS安全连接

    • 添加用户认证系统

    • 防止CSRF攻击

  3. 性能优化

    • 学习异步Web服务器

    • 实现缓存策略

    • 优化内存使用

7.2 相关资源推荐

  1. ESP32开发入门(七):HTTP客户端开发实践

  2. ESP32官方WebServer示例

  3. ArduinoJson文档

  4. ESP32 HTTPS服务器指南

相关文章:

  • 请求参数:Header 参数,Body 参数,Path 参数,Query 参数分别是什么意思,什么样的,分别通过哪个注解获取其中的信息
  • 【Leetcode】系列之206反转链表
  • 需求变更控制不严,如何防止项目范围扩大
  • Express知识框架
  • Day22打卡-复习
  • PHP编写图书信息爬虫程序
  • 跨域问题深度解析与解决方案
  • rbac模型详解
  • Go语言多线程爬虫与代理IP反爬
  • 【Java继承】——面向对象编程的基石
  • 从经典力扣题发掘DFS与记忆化搜索的本质 -从矩阵最长递增路径入手 一步步探究dfs思维优化与编程深度思考
  • 互联网大厂Java求职面试实战:Spring Boot与微服务场景深度解析
  • 鸿蒙HarmonyOS list优化一: list 结合 lazyforeach用法
  • yarn workspace使用指南
  • 精品可编辑PPT | 全面风险管理信息系统项目建设风控一体化标准方案
  • 数据库实验报告 SQL SERVER 2008的基本操作 1
  • 企业对数据集成工具的需求及 ETL 工具工作原理详解
  • 一键生成达梦、Oracle、MySQL 数据库 ER 图!解锁高效数据库设计!
  • 《基于 Kubernetes 的 WordPress 高可用部署实践:从 MariaDB 到 Nginx 反向代理》
  • PostgreSQL 序列(Sequence) 与 Oracle 序列对比
  • 张笑宇:物质极大丰富之后,我们该怎么办?
  • “犍陀罗艺术与亚洲文明”在浙大对外展出
  • 习近平圆满结束对俄罗斯国事访问并出席纪念苏联伟大卫国战争胜利80周年庆典
  • 重庆大学通报本科生发14篇SCI论文:涉事学生及其父亲被处理
  • 总奖池超百万!第五届七猫现实题材征文大赛颁奖在即
  • 重温经典|《南郭先生》:不模仿别人,不重复自己