ESP32-CAM发送图片后出现HTTP POST错误-11的问题求助
ESP32-CAM HTTP POST报错-11问题排查与解决
问题概述
基于ESP32-CAM开发的项目,摄像头捕获图片后通过HTTP POST发送至服务器,服务器接收图片并调用AI API处理。图片能正常传输到服务器,但ESP32在发送约6秒后报错Error sending HTTP POST request: -11,且不等待服务器响应。已尝试延长超时时间,问题依然存在。
原因分析
- HTTPClient超时设置未生效:当前代码中
setup()里设置的http.setTimeout(60000)仅对setup内的http实例生效,captureAndSendPhoto()中新建的HTTPClient实例未设置超时,使用默认的5秒超时,与报错出现的时间(约6秒)吻合。 - 服务器响应延迟:服务器接收图片后,还要调用外部AI API,整个处理流程耗时超过ESP32默认的HTTP超时时间,导致ESP32提前断开连接并报错。
- HTTP连接资源未释放:代码中调用
http.POST()后未调用http.end(),可能导致连接池耗尽或后续请求异常。
解决建议
1. 为每个HTTPClient实例设置足够长的超时
在captureAndSendPhoto()中创建HTTPClient后,立即设置超时时间,覆盖默认的5秒限制。
2. 确保HTTP连接资源被正确释放
每次请求完成后调用http.end(),避免资源泄漏。
3. 优化服务器处理流程(可选)
- 服务器收到图片后,立即返回响应给ESP32,再异步处理AI API调用,避免ESP32长时间等待。
- 检查服务器调用AI API的耗时,优化接口响应速度。
修改后的ESP32代码
#include "WiFi.h" #include "esp_camera.h" #include "Arduino.h" #include "soc/soc.h" // Disable brownout problems #include "soc/rtc_cntl_reg.h" // Disable brownout problems #include "driver/rtc_io.h" #include <HTTPClient.h> // Replace with your network credentials const char* ssid = "WIFI_NAME"; const char* password = "WIFI_PSSWD"; // Replace with your PHP page URL const char* phpURL = "http://192.168.0.116:80/index.php"; // OV2640 camera module pins (CAMERA_MODEL_AI_THINKER) #define PWDN_GPIO_NUM 32 #define RESET_GPIO_NUM -1 #define XCLK_GPIO_NUM 0 #define SIOD_GPIO_NUM 26 #define SIOC_GPIO_NUM 27 #define Y9_GPIO_NUM 35 #define Y8_GPIO_NUM 34 #define Y7_GPIO_NUM 39 #define Y6_GPIO_NUM 36 #define Y5_GPIO_NUM 21 #define Y4_GPIO_NUM 19 #define Y3_GPIO_NUM 18 #define Y2_GPIO_NUM 5 #define VSYNC_GPIO_NUM 25 #define HREF_GPIO_NUM 23 #define PCLK_GPIO_NUM 22 void setup() { // Serial port for debugging purposes Serial.begin(115200); // Connect to Wi-Fi WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(1000); Serial.println("Connecting to WiFi..."); } // Turn-off the 'brownout detector' WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0); // OV2640 camera module pins camera_config_t config; config.ledc_channel = LEDC_CHANNEL_0; config.ledc_timer = LEDC_TIMER_0; config.pin_d0 = Y2_GPIO_NUM; config.pin_d1 = Y3_GPIO_NUM; config.pin_d2 = Y4_GPIO_NUM; config.pin_d3 = Y5_GPIO_NUM; config.pin_d4 = Y6_GPIO_NUM; config.pin_d5 = Y7_GPIO_NUM; config.pin_d6 = Y8_GPIO_NUM; config.pin_d7 = Y9_GPIO_NUM; config.pin_xclk = XCLK_GPIO_NUM; config.pin_pclk = PCLK_GPIO_NUM; config.pin_vsync = VSYNC_GPIO_NUM; config.pin_href = HREF_GPIO_NUM; config.pin_sscb_sda = SIOD_GPIO_NUM; config.pin_sscb_scl = SIOC_GPIO_NUM; config.pin_pwdn = PWDN_GPIO_NUM; config.pin_reset = RESET_GPIO_NUM; config.xclk_freq_hz = 20000000; config.pixel_format = PIXFORMAT_JPEG; if (psramFound()) { config.frame_size = FRAMESIZE_UXGA; config.jpeg_quality = 10; config.fb_count = 2; } else { config.frame_size = FRAMESIZE_SVGA; config.jpeg_quality = 12; config.fb_count = 1; } // Camera init esp_err_t err = esp_camera_init(&config); if (err != ESP_OK) { Serial.printf("Camera init failed with error 0x%x", err); ESP.restart(); } //Let the camera adapt to the environment (light, exposure, etc..) camera_fb_t* fb = nullptr; // Skip first N frames. for (int i = 0; i < 3; i++) { fb = esp_camera_fb_get(); esp_camera_fb_return(fb); fb = nullptr; delay(500); // delay between photos } // Take photo and send to PHP page captureAndSendPhoto(); } void loop() { delay(10000); captureAndSendPhoto(); } void captureAndSendPhoto() { camera_fb_t* fb = NULL; // pointer // Take a photo with the camera Serial.println("Taking a photo..."); fb = esp_camera_fb_get(); if (!fb) { Serial.println("Camera capture failed"); return; } // Send HTTP POST request to PHP page Serial.println("Sending photo to PHP page..."); HTTPClient http; http.setTimeout(60000); // 设置60秒超时,覆盖默认值 http.begin(phpURL); http.addHeader("Content-Type", "image/jpeg"); int httpResponseCode = http.POST((uint8_t*)fb->buf, fb->len); // Check for errors if (httpResponseCode > 0) { Serial.print("HTTP Response code: "); Serial.println(httpResponseCode); // Print the content of the page String response = http.getString(); Serial.println("Response content:"); Serial.println(response); } else { Serial.print("Error sending HTTP POST request: "); Serial.println(httpResponseCode); } // 释放HTTP连接资源 http.end(); // Free up memory esp_camera_fb_return(fb); }
服务器端优化建议(异步处理)
修改PHP代码,在保存图片后立即返回响应,通过异步任务处理AI API调用:
<?php // Check if raw image data was sent via POST if ($_SERVER['REQUEST_METHOD'] === 'POST' && null !== ($rawData = file_get_contents("php://input"))) { // Retrieve the API key from the request header $headers = getallheaders(); $apiKeyShuttle = isset($headers['Shuttle_API_Key']) ? str_replace('Bearer ', '', $headers['Shuttle_API_Key']) : ''; $apiKeyClarifai = isset($headers['Clarifai_API_Key']) ? str_replace('Bearer ', '', $headers['Clarifai_API_Key']) : ''; // Define the directory to save the image $uploadDir = '/var/www/html/'; // Change this to the desired directory // Generate a unique filename for the image $filename = uniqid() . '.jpg'; // Combine the directory and filename $filePath = $uploadDir . $filename; // Save the raw image data to a file if (file_put_contents($filePath, $rawData) !== false) { // 立即返回响应给ESP32 http_response_code(200); echo "Image saved, processing in background."; flush(); ob_flush(); // 异步处理AI API调用 ignore_user_abort(true); set_time_limit(0); $image= "http://theyoungmaker.ddns.net:8332/" . $filename; $Image_AI_Speech_URL = "http://whisper.local/Image_AI_Speech.php"; $json = json_encode(['image' => $image]); $ch = curl_init($Image_AI_Speech_URL); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, $json); curl_setopt($ch, CURLOPT_HTTPHEADER, [ "Shuttle_API_Key: Bearer $apiKeyShuttle", "Clarifai_API_Key: Bearer $apiKeyClarifai", "Content-Type: application/json" ]); $imageResponse = curl_exec($ch); $err = curl_error($ch); curl_close($ch); // 可将处理结果写入日志 file_put_contents('/var/log/ai_process.log', date('Y-m-d H:i:s') . ' - ' . ($err ? $err : $imageResponse) . PHP_EOL, FILE_APPEND); } else { // If unable to save the file, return an error message http_response_code(500); echo "Error: Failed to save image."; } } else { // If no image data was received, return an error message http_response_code(400); echo "Error: No image data received."; } ?>
内容的提问来源于stack exchange,提问作者Loic Daigle
相关产品推荐
相关产品推荐

