想象一下,你家的台灯能听懂浏览器说的话——这不是魔法,而是ESP32 WebServer库的功劳。这个只有指甲盖大小的芯片,内置了完整的Wi-Fi和TCP/IP协议栈,让它摇身一变成为物联网世界的"翻译官"。我去年用这个库给朋友做了个智能鱼缸控制器,他坐在办公室就能通过手机查看水温、投喂鱼食,简直像拥有了超能力。
WebServer库本质上是个HTTP协议转换器,把网络请求变成ESP32能理解的信号。就像餐厅里的服务员,它负责接收顾客(客户端)的点单(HTTP请求),后厨(ESP32)做好菜后,再由服务员把菜品(响应)端回去。最妙的是,这个"服务员"不需要额外工资——库文件只有不到20KB,在ESP32的520KB SRAM里根本不算什么。
我的工作台上常备三样神器:ESP32-DevKitC开发板(30块钱比奶茶还便宜)、Micro-USB数据线(建议选带磁环的抗干扰款)、以及DHT22温湿度传感器(后续项目会用上)。第一次使用时容易栽在驱动问题上——Windows用户记得安装CP210x USB转串口驱动,不然设备管理器里会显示黄色感叹号。
打开Arduino IDE后别急着写代码,先做这三步:
https://dl.espressif.com/dl/package_esp32_index.json有个坑我踩过三次:如果编译时提示"WebServer.h not found",八成是没选对开发板型号。正确路径是:工具→开发板→ESP32 Arduino→对应的ESP32型号。
cpp复制#include <WiFi.h>
#include <WebServer.h>
const char* ssid = "你的Wi-Fi";
const char* password = "密码";
WebServer server(80); // 80是HTTP默认端口
void handleRoot() {
server.send(200, "text/plain", "欢迎来到我的物联网世界");
}
void setup() {
Serial.begin(115200);
WiFi.begin(ssid, password);
while(WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("\nIP地址: ");
Serial.println(WiFi.localIP());
server.on("/", handleRoot);
server.begin();
}
void loop() {
server.handleClient();
}
这段代码就像物联网界的"Hello World":
server.on()相当于给服务器装了个门铃,告诉它当有人按"/"这个门铃时就调用handleRoot函数server.send()的三个参数分别是HTTP状态码(200表示成功)、内容类型(text/plain是纯文本)、以及实际内容上周有个学员问我为什么浏览器显示"无法连接",检查后发现四个典型问题:
建议在setup()里加个WiFi.setAutoReconnect(true),这样网络波动时能自动重连。如果要用静态IP,可以这样配置:
cpp复制IPAddress local_IP(192,168,1,100);
IPAddress gateway(192,168,1,1);
IPAddress subnet(255,255,255,0);
WiFi.config(local_IP, gateway, subnet);
物联网设备最常用的就是参数传递。比如控制LED亮度,可以通过URL传参:http://192.168.1.100/led?brightness=75
服务端这样处理:
cpp复制void handleLED() {
if(server.hasArg("brightness")) {
int brightness = server.arg("brightness").toInt();
analogWrite(LED_PIN, brightness);
server.send(200, "text/plain", "亮度已设置为" + String(brightness));
} else {
server.send(400, "text/plain", "缺少brightness参数");
}
}
// 在setup()中添加
server.on("/led", handleLED);
POST请求更适合传输敏感数据,比如密码。接收JSON格式POST请求的示例:
cpp复制#include <ArduinoJson.h>
void handleLogin() {
if(server.method() == HTTP_POST) {
DynamicJsonDocument doc(256);
deserializeJson(doc, server.arg("plain"));
String user = doc["username"];
String pass = doc["password"];
// 验证逻辑...
}
}
直接拼接HTML字符串太痛苦了,我推荐两种方案:
cpp复制const char MAIN_page[] PROGMEM = R"=====(
<!DOCTYPE html>
<html>
<body>
<h1>实时温湿度</h1>
<p>温度: %TEMPERATURE%°C</p>
</body>
</html>
)=====";
String processor(const String& var){
if(var == "TEMPERATURE"){
return String(dht.readTemperature());
}
return String();
}
server.send(200, "text/html", processor(MAIN_page));
cpp复制#include <SPIFFS.h>
void handleRoot() {
File file = SPIFFS.open("/index.html", "r");
server.streamFile(file, "text/html");
file.close();
}
// setup()中需要先初始化SPIFFS
if(!SPIFFS.begin(true)){
Serial.println("SPIFFS初始化失败");
}
我用DHT22+BMP280+光敏电阻做了个多功能监测站,接线如下:
| 传感器 | ESP32引脚 | 备注 |
|---|---|---|
| DHT22 | GPIO4 | 需要4.7K上拉电阻 |
| BMP280 | GPIO21/22 | I2C通信 |
| 光敏电阻 | GPIO34 | 只能用于ADC输入 |
特别注意:ESP32的ADC引脚(32-39)电压范围是0-3.3V,千万别接5V传感器!
RESTful风格的API设计示例:
cpp复制// 获取所有数据
server.on("/api/data", HTTP_GET, [](){
DynamicJsonDocument doc(1024);
doc["temp"] = readDHT22();
doc["pressure"] = readBMP280();
String output;
serializeJson(doc, output);
server.send(200, "application/json", output);
});
// 控制设备
server.on("/api/led", HTTP_POST, [](){
// 解析参数并控制LED
});
添加CORS支持让网页能跨域访问:
cpp复制server.sendHeader("Access-Control-Allow-Origin", "*");
server.sendHeader("Access-Control-Max-Age", "10000");
WebServer库默认会预分配4000字节缓冲区,如果处理大量数据可以调整:
cpp复制WebServer server(80);
server.setContentLength(8192); // 设置更大的内容长度
使用String对象时要小心内存碎片,我习惯用静态缓冲区:
cpp复制char buffer[512];
snprintf(buffer, sizeof(buffer), "当前温度: %.1f°C", temperature);
server.send(200, "text/plain", buffer);
基础认证是最简单的保护措施:
cpp复制server.on("/admin", [](){
if(!server.authenticate("admin", "s3cr3t")){
return server.requestAuthentication();
}
server.send(200, "text/plain", "机密区域");
});
定期检查库版本也很重要,去年就爆出过缓冲区溢出漏洞。在Arduino库管理器中搜索"WebServer",确保安装的是最新版。
当页面加载异常时,我通常这样排查:
一个实用的调试中间件:
cpp复制void debugMiddleware(String path) {
Serial.printf("[%lu] %s %s\n", millis(), server.method() == HTTP_GET ? "GET" : "POST", path.c_str());
for(int i=0; i<server.args(); i++){
Serial.printf(" %s: %s\n", server.argName(i).c_str(), server.arg(i).c_str());
}
}
// 在每个handler开头调用
debugMiddleware(server.uri());
当基础功能跑通后,可以尝试:
我最喜欢的功能是结合SPIFFS和gzip压缩,把网页加载时间从2秒降到200毫秒。具体做法是在PlatformIO的构建脚本中添加:
ini复制board_build.spiffs_compress = true
board_build.spiffs_blocksize = 8192