You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ESP32-CAM发送图片后出现HTTP POST错误-11的问题求助

ESP32-CAM HTTP POST报错-11问题排查与解决

问题概述

基于ESP32-CAM开发的项目,摄像头捕获图片后通过HTTP POST发送至服务器,服务器接收图片并调用AI API处理。图片能正常传输到服务器,但ESP32在发送约6秒后报错Error sending HTTP POST request: -11,且不等待服务器响应。已尝试延长超时时间,问题依然存在。

原因分析

  1. HTTPClient超时设置未生效:当前代码中setup()里设置的http.setTimeout(60000)仅对setup内的http实例生效,captureAndSendPhoto()中新建的HTTPClient实例未设置超时,使用默认的5秒超时,与报错出现的时间(约6秒)吻合。
  2. 服务器响应延迟:服务器接收图片后,还要调用外部AI API,整个处理流程耗时超过ESP32默认的HTTP超时时间,导致ESP32提前断开连接并报错。
  3. 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 17:19:51