ESP32. Не передается файл на сервер POST запросом

Добрый день всем! Нужна помощь по программированию ESP32 . Мне нужно передать файл (пока текстовый, для проверки) на сервер с помощью POST запроса. Написал PHP скрипт и разместил его на сервере. Тестировал передачу файлов на этот сервер с помощью программы Postman. Всё работает, а вот с ESP32 файл не отправляется. Ответ с кодом “200” от сервера приходит но php скрипт отвечает что файл не принят. Я в коде для ЕСПшки установил точно такие заголовки в запросе как и в программе Postman, но всё равно файл не отправляется.
Есть подозрение что я неправильно помещаю файл в буфер для передачи.
Вот код ЕСП32:

#include <WiFi.h>
#include <HTTPClient.h>
#include <SPIFFS.h>
#include <random>

const char* ssid = "Golfstream";
const char* password = "lagrange@@@";


void setup() {
  Serial.begin(115200);
  SPIFFS.begin();
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("Connecting to WiFi...");
  }
  Serial.println("Connected to WiFi");

  // Отправка POST-запроса на сервер
  sendFileToServer();
}


void loop() {
  //---------------//
}



String generateBoundary() {
  const String characters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
  std::random_device rd;
  std::mt19937 generator(rd());
  std::uniform_int_distribution<int> distribution(0, characters.length() - 1);
  
  String boundary;
  for (int i = 0; i < 16; ++i) {
    boundary += characters[distribution(generator)];
  }
  
  return boundary;
}


void sendFileToServer() {
  // Подключение к серверу
  HTTPClient http;
  http.begin("http://MyServerIpAddress:8081/site/input.php"); 

  // Открытие файла для чтения
  File file = SPIFFS.open("/test.txt"); 

  // Если файл успешно открыт
  if (file) {
    // Получение размера файла
    size_t fileSize = file.size();

    // Создание буфера для чтения файла
    uint8_t *buffer = new uint8_t[fileSize];

    // Чтение содержимого файла в буфер
    file.read(buffer, fileSize);

    // Закрытие файла
    file.close();

    String boundary = generateBoundary();
    Serial.print("boundary = ");
    Serial.println(boundary);
    Serial.print("FileSize = ");
    Serial.println(fileSize);

    // Формирование заголовка Content-Type с указанием boundary
    String contentType = "multipart/form-data; boundary=" + boundary;

    
    // Отправка POST-запроса с данными файла
    http.addHeader("Content-Type", contentType);
    http.addHeader("Content-Length", String(fileSize));
    http.addHeader("Host", "MyServerIpAddress"); //
    
    int httpResponseCode = http.POST(buffer, fileSize);

    // Проверка ответа сервера
    if (httpResponseCode > 0) {
      Serial.printf("HTTP Response code: %d\n", httpResponseCode);
      String response = http.getString();
      Serial.println(response);
    } else {
      Serial.printf("Error sending POST request: %s\n", http.errorToString(httpResponseCode).c_str());
    }

    // Освобождение памяти буфера
    delete[] buffer;
  } else {
    Serial.println("Failed to open file for reading");
  }

  // Закрытие соединения с сервером
  http.end();
}

Код PHP скрипта на сервере:

<?php
// Путь, где будет сохранен принятый файл
$uploadDirectory = "ESP32/wav/";

// Проверяем, был ли отправлен файл
if(isset($_FILES['file']) && $_FILES['file']['error'] === UPLOAD_ERR_OK) {
    $tempFile = $_FILES['file']['tmp_name'];
    $targetFile = $uploadDirectory . "test.txt";

    // Перемещаем файл в желаемую директорию
    if(move_uploaded_file($tempFile, $targetFile)) {
        // Файл успешно сохранен
        echo "File uploaded successfully.";
    } else {
        // Ошибка при сохранении файла
        echo "Failed to upload file.";
    }
} else {
    // Ошибка при получении файла
    echo "Error receiving file.";

}
?>

При таком подозрении нужно сразу обрубать хвосты и делать что-то типа:

http.addHeader("Content-Type", "text/plain");
...
int httpResponseCode = http.POST("Hello, World!");

Заработает - двигаться дальше.

1 лайк

И отладку на стороне сервера подключить…

if (!empty($_POST))
{
	echo 'Файл получен';
}else{
echo 'Файл НЕ получен';
}
1 лайк

Попробовал передавать просто текст. Такая же херня. От сервиса Postman передается а из ESPшки нет. Лог access.log на сервере:

Зеленым выделены строки запроса при отправке из Postman, красным из ESP32

Сервер в LAN же, не в энторнетах?

Ты ставишь заголовок multipart/form-data, но не формируешь правильное тело, а отправляешь тупо содержимое файла, без разделителей и всего положенного этому формату. Внимательно прочитай что такое multipart/form-data

1 лайк

Сервер находится в Интернете.

Но даже текст не отправляется, я проверил как мне посоветовали:

http.addHeader("Content-Type", "text/plain");
int httpResponseCode = http.POST("Hello, World!");

Ну, в энторнетах ежели, то поменяй http useragent на браузерный. Щас это модная проблема, по ходу дела.

??? Какое это имеет отношение хоть к чему-то? Ладно, удачи. Не хочешь разбираться - мне это тем более не надо.

Ну как какое отношение? Я сделал как посоветовал sadman41, попробовал передать просто текст, тоже не передается.

Вот тут тоже тыкались-мыкались, оказалось дело в юзерагенте.

откуда это видно? я так понимаю у тебя панель Веста?

нет, не Веста. У меня на сервере скрипт php, я сделал немного другой, для приема и записи текста в файл, не такой как разместил в начале поста (для приема файла). Пока разбираюсь с передачей просто текста.

<?php
// Путь, где будет сохранен принятый файл
$uploadDirectory = "ESP32/wav/";

// Проверяем, был ли отправлен текст
if(isset($_POST['text'])) {
    $text = $_POST['text'];
    
    // Создаем текстовый файл
    $filename = "hello.txt";
    $targetFile = $uploadDirectory . $filename;
    
    // Открываем файл на запись
    $file = fopen($targetFile, "w");
    
    if ($file) {
        // Записываем текст в файл
        fwrite($file, $text);
        
        // Закрываем файл
        fclose($file);
        
        // Файл успешно сохранен
        echo "File uploaded successfully.";
    } else {
        // Ошибка при создании файла
        echo "Failed to create file.";
    }
} else {
    // Ошибка при получении текста
    echo "Error receiving text.";
}
?>

Когда проверяю передачу текста с помощью Pоstman, получаю код ответа сервера “200” и ответ от скрипта “File uploaded successfully”, а когда передаю с ESP32 то получаю код ответа “200” и “Error receiving text.” Еще непонятно, почему с Postmana передача удачная только если параметры установлены: Content-Type: multipart/form-data; boundary=ITv5aK3F89kPtGRW и Content-Length: 90. Ведь передаю простой текст и его длина всего, например 12 байт. Когда в Postman устанавливаю Content-Length: 12 или Content-Type: “text/plain”, получаю код ответа “200” и “Error receiving text.”

через url это делается так:

   //Check WiFi connection status
    if (WiFi.status() == WL_CONNECTED) {
      WiFiClient client;
      HTTPClient http;
      http.setUserAgent(F("Mozilla/5.0"));

      // вызвать процедуру сбора строки для POST
      //      ReadPostData();

E200:
      http.begin(client, serverName);

      http.addHeader("Content-Type", "application/x-www-form-urlencoded");
      int httpResponseCode = http.POST(newData);
      Serial.print("HTTP Response code: ");
      Serial.println(httpResponseCode);

      if (!(httpResponseCode == 200)) { // долбим пока не примет данные
        delay(3000);
        goto E200;
      }

      // Free
      http.end();
    }