一、HTTP协议基础
HTTP(Hyper Text Transfer Protocol)作为互联网基础协议,采用请求-响应模型工作:
1.1 HTTP请求组成
c
GET /uri?query1=value1 HTTP/1.1 // 请求行(方法+URI+协议版本)
Host: example.com // 请求头(键值对)
User-Agent: curl/7.68.0
Accept: */*
// 空行分隔
body_data... // 请求体(POST/PUT时存在)
1.2 HTTP响应结构
c
HTTP/1.1 200 OK // 状态行(版本+状态码+原因短语)
Content-Type: text/html // 响应头
Content-Length: 123
// 空行分隔
<html>...</html> // 响应体
常见状态码含义
状态码 | 含义 | 典型场景 |
---|---|---|
200 | OK | 请求成功 |
301 | 永久重定向 | 网站改版 |
404 | Not Found | URI不存在 |
500 | 服务器内部错误 | 程序崩溃 |
二、ESP-HTTP-Server核心API
ESP-IDF提供轻量级HTTP服务器组件,核心接口如下:
2.1 服务器初始化
c
// 创建默认配置
httpd_config_t config = HTTPD_DEFAULT_CONFIG();
config.server_port = 80; // 设置监听端口
// 启动HTTP服务器
httpd_handle_t server;
esp_err_t ret = httpd_start(&server, &config);
2.2 URI处理器注册
c
typedef struct {
const char *uri;
httpd_method_t method;
esp_err_t (*handler)(httpd_req_t *r);
void *user_ctx;
} httpd_uri_t;
// 示例:注册GET处理器
httpd_register_uri_handler(server, &(httpd_uri_t){
.uri = "/api/data",
.method = HTTP_GET,
.handler = data_get_handler,
.user_ctx = NULL
});
2.3 请求解析关键API
函数 | 功能描述 |
---|---|
httpd_req_get_url_query_len() |
获取查询字符串长度 |
httpd_req_get_url_query_str() |
获取完整查询字符串 |
httpd_query_key_value() |
解析特定键值参数 |
httpd_req_recv() |
接收请求体数据 |
三、核心实现代码
3.1 GET请求处理
c
esp_err_t get_handler(httpd_req_t *req) {
// 构造响应
const char resp[] = "{\"status\":\"OK\",\"value\":25}";
// 设置JSON类型响应头
httpd_resp_set_type(req, "application/json");
// 发送响应
httpd_resp_send(req, resp, HTTPD_RESP_USE_STRLEN);
return ESP_OK;
}
3.2 POST请求处理
c
esp_err_t post_handler(httpd_req_t *req) {
char content[100];
int recv_size = MIN(req->content_len, sizeof(content)-1);
// 接收数据
int ret = httpd_req_recv(req, content, recv_size);
if (ret <= 0) {
if (ret == HTTPD_SOCK_ERR_TIMEOUT) {
httpd_resp_send_408(req);
}
return ESP_FAIL;
}
content[ret] = '\0'; // 添加字符串终止符
// 处理接收的数据(示例:控制LED)
if (strstr(content, "led=on")) {
gpio_set_level(LED_GPIO, 1);
}
// 发送响应
httpd_resp_send(req, "CMD_EXECUTED", 12);
return ESP_OK;
}
3.3 URI处理器绑定
c
// GET端点配置
httpd_uri_t get_endpoint = {
.uri = "/control",
.method = HTTP_GET,
.handler = get_handler,
.user_ctx = NULL
};
// POST端点配置
httpd_uri_t post_endpoint = {
.uri = "/control",
.method = HTTP_POST,
.handler = post_handler,
.user_ctx = NULL
};
// 注册处理器
void register_handlers(httpd_handle_t server) {
httpd_register_uri_handler(server, &get_endpoint);
httpd_register_uri_handler(server, &post_endpoint);
}
四、实战应用示例
4.1 创建WiFi热点提供HTTP服务
c
void app_main() {
// 初始化NVS
nvs_flash_init();
// 创建AP模式热点
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
esp_wifi_init(&cfg);
wifi_config_t wifi_config = {
.ap = {
.ssid = "ESP32_AP",
.password = "12345678",
.max_connection = 4,
.authmode = WIFI_AUTH_WPA_WPA2_PSK
}
};
esp_wifi_set_mode(WIFI_MODE_AP);
esp_wifi_set_config(ESP_IF_WIFI_AP, &wifi_config);
esp_wifi_start();
// 启动HTTP服务器
httpd_handle_t server = start_webserver();
}
4.2 关键功能测试方法
测试GET请求
bash
curl "http://192.168.4.1/control?led=on"
响应示例:
json
{"status":"OK","value":1}
测试POST请求
bash
curl -X POST -d "brightness=80" http://192.168.4.1/control
响应示例:
CMD_EXECUTED
实时调试输出
c
I (1254) HTTP_SERVER: Received 12 bytes: brightness=80
I (1256) GPIO: LED brightness set to 80%
4.3 动态URI管理
c
// 动态注销URI
httpd_unregister_uri(server, "/old_api");
// 注册新URI
httpd_register_uri_handler(server, &(httpd_uri_t){
.uri = "/new_api",
.method = HTTP_GET,
.handler = new_api_handler
});
// 自定义错误处理
httpd_register_err_handler(server, HTTPD_404_NOT_FOUND, custom_404_handler);
五、进阶技巧
5.1 分块传输大文件
c
FILE *file = fopen("/spiffs/image.jpg", "rb");
const size_t CHUNK_SIZE = 1024;
uint8_t chunk[CHUNK_SIZE];
while (fread(chunk, 1, CHUNK_SIZE, file) > 0) {
httpd_resp_send_chunk(req, (char*)chunk, CHUNK_SIZE);
}
httpd_resp_send_chunk(req, NULL, 0); // 结束传输
fclose(file);
5.2 安全增强方案
c
// Basic身份验证
char auth_header[150];
size_t auth_len = httpd_req_get_hdr_value_len(req, "Authorization");
if (auth_len > 0) {
httpd_req_get_hdr_value_str(req, "Authorization", auth_header, sizeof(auth_header));
if (strstr(auth_header, "Basic dXNlcjpwYXNz") == NULL) { // user:pass的base64
httpd_resp_set_status(req, "401 Unauthorized");
httpd_resp_set_hdr(req, "WWW-Authenticate", "Basic realm=\"ESP32\"");
httpd_resp_send(req, NULL, 0);
return ESP_OK;
}
}
5.3 性能优化参数
c
httpd_config_t config = HTTPD_DEFAULT_CONFIG();
config.uri_match_fn = httpd_uri_match_wildcard; // 启用通配符匹配
config.max_open_sockets = 6; // 最大并发连接数
config.stack_size = 10240; // 任务堆栈大小
config.lru_purge_enable = true; // 启用LRU连接清理
六、常见问题排查
6.1 典型错误解决方案
错误现象 | 可能原因 | 解决方案 |
---|---|---|
启动失败 (ESP_ERR_INVALID_ARG) | 端口被占用 | 更换端口或重启设备 |
接收数据不完整 | 缓冲区太小 | 增大接收缓冲区 |
响应时间过长 | 处理器阻塞 | 优化处理逻辑或启用分块传输 |
OTA升级失败 | 分区表配置错误 | 检查分区表设置 |
6.2 调试技巧
c
// 启用详细日志
esp_log_level_set("httpd", ESP_LOG_VERBOSE);
// 查看内存使用情况
ESP_LOGI(TAG, "Free heap: %d", esp_get_free_heap_size());
// 网络抓包分析
// 使用Wireshark监听端口80流量
实测数据参考:
- 最小内存占用:~20KB RAM
- 最大并发连接:6-8个(根据配置)
- 请求处理延迟:<50ms(简单请求)
完整工程代码 :GitHub仓库链接
参考资料: