一、HTTP協議基礎
HTTP(Hyper Text Transfer Protocol)作為互聯網基礎協議,采用請求-響應模型工作:
1.1 HTTP請求組成
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響應結構
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 服務器初始化
// 創建默認配置
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處理器注冊
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請求處理
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請求處理
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處理器綁定
// 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服務
void app_main() {// 初始化NVSnvs_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請求
curl "http://192.168.4.1/control?led=on"
響應示例:
{"status":"OK","value":1}
測試POST請求
curl -X POST -d "brightness=80" http://192.168.4.1/control
響應示例:
CMD_EXECUTED
實時調試輸出
I (1254) HTTP_SERVER: Received 12 bytes: brightness=80
I (1256) GPIO: LED brightness set to 80%
4.3 動態URI管理
// 動態注銷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 分塊傳輸大文件
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 安全增強方案
// 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的base64httpd_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 性能優化參數
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 調試技巧
// 啟用詳細日志
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倉庫鏈接
參考資料:
- ESP-IDF HTTP Server官方文檔
- HTTP狀態碼詳解