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

ESP32(IDF4.4)HTTP POST上传JPEG至服务器失败求助

问题与解决

我用搭载IDF 4.4的ESP32,想通过HTTP POST把相机读取的JPEG字节数组上传到PHP服务器,服务器仅需存储图片。PC端Python脚本测试正常,服务器$_FILES能拿到数据;但ESP32上传时无报错,服务器的$_FILES和$_POST却全为空。不清楚怎么在ESP32的POST请求里加Python和PHP脚本中用于识别文件的"image"键,同时想了解除了查看超全局变量外,还有哪些调试服务器接收内容的方法。

核心问题原因

Python的requests.post(url, files=file)会自动使用multipart/form-data格式上传文件,这是PHP的$_FILES能识别的标准文件上传格式。但你的ESP32代码直接把JPEG二进制流作为POST内容,设置的Content-Type为image/jpeg,这种方式PHP不会将其解析到$_FILES中,所以服务器端看不到数据。

ESP32代码修正方案

要让ESP32发送符合multipart/form-data格式的请求,需手动构造包含"image"字段的请求体、boundary分隔符及文件内容。修改后的代码示例:

#define _SERVER_URL    "http://X.X.X.X/upload.php"
// 定义唯一的boundary,用于分隔multipart内容段
#define BOUNDARY "----WebKitFormBoundary7MA4YWxkTrZu0gW"

esp_http_client_config_t _server_config = {
    .url = _SERVER_URL,
    .method = HTTP_METHOD_POST,
    .event_handler = _server_httpEventHandler
};

esp_http_client_handle_t _server_client = NULL;

void server_sendJpeg(uint8_t* jpeg, uint32_t jpegSize)
{
    // 计算multipart请求体总长度
    size_t boundary_len = strlen(BOUNDARY);
    size_t header_len = snprintf(NULL, 0, 
        "--%s\r\nContent-Disposition: form-data; name=\"image\"; filename=\"cam.jpg\"\r\nContent-Type: image/jpeg\r\n\r\n", 
        BOUNDARY);
    size_t footer_len = snprintf(NULL, 0, "\r\n--%s--\r\n", BOUNDARY);
    size_t total_len = header_len + jpegSize + footer_len;

    // 分配内存存储完整请求体
    uint8_t* post_data = malloc(total_len);
    if (!post_data) {
        // 内存分配失败处理
        return;
    }

    // 拼接请求体头部
    size_t offset = sprintf((char*)post_data, 
        "--%s\r\nContent-Disposition: form-data; name=\"image\"; filename=\"cam.jpg\"\r\nContent-Type: image/jpeg\r\n\r\n", 
        BOUNDARY);
    // 复制JPEG数据
    memcpy(post_data + offset, jpeg, jpegSize);
    offset += jpegSize;
    // 拼接尾部
    sprintf((char*)post_data + offset, "\r\n--%s--\r\n", BOUNDARY);

    _server_client = esp_http_client_init(&_server_config);
    esp_http_client_set_method(_server_client, HTTP_METHOD_POST);
    // 设置正确的Content-Type,带上boundary
    char content_type[100];
    snprintf(content_type, sizeof(content_type), "multipart/form-data; boundary=%s", BOUNDARY);
    esp_http_client_set_header(_server_client, "Content-Type", content_type);
    // 设置请求体长度
    char total_len_str[10];
    snprintf(total_len_str, sizeof(total_len_str), "%u", total_len);
    esp_http_client_set_header(_server_client, "Content-Length", total_len_str);
    // 设置POST请求体
    esp_http_client_set_post_field(_server_client, (const char*)post_data, total_len);
    
    esp_http_client_perform(_server_client);

    // 释放内存并清理客户端
    free(post_data);
    esp_http_client_cleanup(_server_client);
}

服务器端调试方法

除打印$_FILES和$_POST外,还有这些实用调试手段:

  • 读取原始请求体:用file_get_contents('php://input')获取完整POST原始数据,直接写入日志查看ESP32发送的内容格式是否正确:
    $raw_data = file_get_contents('php://input');
    file_put_contents('raw_request.txt', $raw_data);
    
  • 打印请求头:用getallheaders()获取所有请求头,检查Content-Type、Content-Length等参数是否符合要求:
    $headers = getallheaders();
    file_put_contents('request_headers.txt', var_export($headers, true));
    
  • 抓包对比:在服务器或ESP32所在网络用tcpdump/Wireshark抓包,对比Python和ESP32发送的请求差异,重点看请求头格式、请求体结构是否一致。

补充注意事项

  • boundary要保证在请求体中唯一,避免和JPEG文件内容重复;
  • 内存分配后务必释放,避免ESP32内存泄漏;
  • 可在ESP32的event_handler中打印请求响应码和响应内容,确认服务器返回信息,辅助排查问题。

内容的提问来源于stack exchange,提问作者Terror404

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 23:52:41