Проблема с отправкой POST-запроса с использованием библиотеки WiFiEsp

Я использую ESP8266 версии 1 с библиотекой WiFiEsp для подключения к WiFi, и это работает просто отлично.

Я настраиваю устройство, используя тот же код, что и в примере WebClientRepeating.

Мне нужно отправить запрос POST вместо запроса GET, но я не могу заставить его работать так, как мне нужно. Если я создам свой запрос POST таким образом, он будет работать просто отлично:

if (client.connect(server, 3005)) {
  Serial.println("Connecting...");

  // отправьте HTTP POST-запрос
  client.println("POST /open/peripherals HTTP/1.1");
  client.println("Host: 192.168.10.137:3005");
  client.println("User-Agent: Arduino/1.0");
  client.println("Connection: close");
  client.println();

  // отметьте время установления соединения
  lastConnectionTime = millis();
}
else {
  // если вы не смогли установить соединение
  Serial.println("Connection failed");
}

Я получаю такой ответ:

[WiFiEsp] Connecting to 192.168.10.137
Connecting...
HTTP/1.1 200 OK
X-Powered-By: Express
Content-Type: application/json; charset=utf-8
Content-Length: 19
ETag: W/"13-jSAaqMh5E3R94/b2aONzvg"
Date: Sun, 13 Nov 2016 10:20:58 GMT
Connection: close

{"temp":"Testdata"}

Однако, если я попытаюсь отправить некоторые данные тела в запросе, произойдет сбой:

if (client.connect(server, 3005)) {
  Serial.println("Connecting...");

  // отправьте HTTP POST-запрос
  client.println("POST /open/peripherals HTTP/1.1");
  client.println("Host: 192.168.10.137:3005");
  client.println("User-Agent: Arduino/1.0");
  client.println("Connection: close");
  client.println("Content-Type: application/x-www-form-urlencoded");
  client.println("Content-Length: 16");
  client.println();
  client.println("temperature=22.7");

  // отметьте время установления соединения
  lastConnectionTime = millis();
}
else {
  // если вы не смогли установить соединение
  Serial.println("Connection failed");
}

Тогда ответ от последовательного вывода будет:

[WiFiEsp] Connecting to 192.168.10.137
Connecting...
[WiFiEsp] >>> TIMEOUT >>>
[WiFiEsp] Data packet send error (1)
[WiFiEsp] Failed to write to socket 0
[WiFiEsp] Disconnecting  0

Однако запрос POST, включая тело, веб-сервер получает нормально, но ответ, отправленный на Arduino, я не могу прочитать, потому что он показывает мне ошибку вместо надлежащего ответа. От моего веб-сервера ответ на вызов POST, который работает, и вызов POST, который не работает, одинаковы.

Кто-нибудь знает, почему это не работает, когда я добавляю Content-Type, Content-Length и некоторые данные тела?

Заранее спасибо!

, 👍2

Обсуждение

Первый ответ не соответствует первому коду. Трудно догадаться, где проблема, без **полного** кода., @Chupo_cro

Длина вашего контента на самом деле составляет 18, учитывая CRLF, добавленный с помощью println()., @SoreDakeNoKoto


2 ответа


2

Ваша проблема в контенте, который вы отправляете. Хотя этот формат хорошо работает, например, в библиотеках Python, эта библиотека, похоже, имеет с ним проблему. Я решил это следующим образом, когда столкнулся с этой проблемой:

//весь ваш остальной код, включая оставшийся HTTP-запрос
String content = "{\"temperature\":\""+String(value)+"\"}";
client.println("Content-Length: 16"); //вставьте, ну, длину вашего контента
client.println(content);
,

0

Кажется, в прошивке AT большинства ESP существует одна серьезная проблема. По умолчанию отправляемые заголовки http включают "Connection: close". Однако прошивка, похоже, глючит и не может справиться с закрытием соединения сервером после отправки ответа. Таким образом, чтобы получить ответ от целевого сервера, вам нужно указать "Connection: keep-alive". Это означает, что вы должны явно добавить это в свой заголовок, поскольку будет добавлено "Connection: close", если не указано иное. Также, чтобы облегчить жизнь библиотеке WifiEsp, вы можете убедиться, что ваш сервер возвращает уже известную строку состояния для библиотеки, например, fx "SEND OK"… Я делаю это на регистраторе барометра, который отправляет данные в MVC Web API, написанный на C#, и он работает идеально...

Вот мой код:

String PostHeader = "POST http://" + server + ":" + String(port) + "/api/values HTTP/1.1\r\n";
PostHeader += "Connection: keep-alive\r\n";
PostHeader += "Content-Type: application/json; charset=utf-8\r\n";
PostHeader += "Host: " + server + ":" + String(port) + "\r\n";
PostHeader += "Content-Length: " + String(jsonString.length()) + "\r\n\r\n";
PostHeader += jsonString;
Serial.println(PostHeader);
client.connect(server.c_str(), port);
client.println(PostHeader);
client.stop();

А полный журнал выглядит так:

POST http://192.168.10.197:8001/api/values HTTP/1.1
Connection: keep-alive
Content-Type: application/json; charset=utf-8
Host: 192.168.10.197:8001
Content-Length: 144

{"IpAddress":"192.168.10.230","MacAddress":"5c:cf:7f:d9:2f:c8","Temperature":34.6,"Pressure":1007,"Altitude":48.48573,"PressureAtSeaLevel":1007}

[WiFiEsp] Connecting to 192.168.10.197
[WiFiEsp] Disconnecting  3

В файле debug.h, расположенном в исходном коде библиотеки WifiEsp, вы можете изменить определение и получить больше вывода на последовательную консоль. Откройте файл и измените

#define _ESPLOGLEVEL_ 3

к

#define _ESPLOGLEVEL_ 4

Сохраните файл и перекомпилируйте/разверните исходный код на Arduino, и вы получите подробную информацию обо всех AT-командах, которые отправляет библиотека, и о том, что библиотека получает в ответ.

,

Connection: close сообщает серверу о необходимости закрыть соединение **после отправки ответа**. Если вы не можете получить ответ с Connection: close, это ваша ошибка: не вините заголовок. Кстати, строки заголовка должны заканчиваться на "\r\n", а не просто на "\n"., @Edgar Bonet

Круто, я долго с этим боролся и экспериментировал со многими вещами, изменение с \r\n на \n было одной из вещей, которые я пробовал (это не сработало). Только забыл вернуть его к тому, что должно быть. Единственный способ заставить его работать с ESP8266 и библиотекой WifiEsp — это пометить заголовок как keep-alive. Я отладил библиотеку и попытался найти что-нибудь, что могло бы на это повлиять, но ничего, скорее всего, это какой-то баг в прошивке AT... Все жалуются на эту проблему на всех сайтах разработчиков, просто хотел добавить свои 2 цента..., @Lennart Jansson

Если это так, то вам следует перефразировать свой ответ: «_В библиотеке XXX [ссылка на обсуждение ошибки] есть известная ошибка, которая не позволяет ей работать с Connection: close, поэтому..._». В существующем виде ваш ответ подразумевает, что использование Connection: close является ошибкой., @Edgar Bonet

Лучше? У меня нет общей ссылки на какие-либо обсуждения по этой теме, потому что все и везде гоняются за дикими гусями, пытаясь решить эту проблему, многие винят библиотеку, но, насколько я могу судить, с ней нет никаких проблем, и она, похоже, делает то, что должна делать :), @Lennart Jansson

Также изменено на \r\n..., @Lennart Jansson

Все еще похоже, что ошибка была в использовании Connection: close, что не так. Я взял на себя смелость отредактировать пост сам, чтобы сделать _явным_ то, что вы обвиняете прошивку в ошибке, которая мешает ей работать с Connection: close., @Edgar Bonet

ответ основан на необоснованных подозрениях. они не соответствуют действительности. библиотека WiFiEsp ожидает SEND OK от прошивки AT, а не от ответа HTTP. Я очень и очень сомневаюсь, что прошивка AT добавляет заголовок HTTP, так как допустимый запрос HTTP заканчивается пустой строкой, а все, что следует после этого, является телом запроса HTTP, @Juraj

Я тоже этого не говорил @Juraj, я сказал, что вам нужно добавить headervalue в качестве обходного пути, поскольку где-то что-то идет не так. HTTP-ответ не дойдет до библиотеки Arduino или WifiEsp должным образом, и вы получите следующий ответ от библиотеки: [WiFiEsp] Ошибка отправки пакета данных (2) [WiFiEsp] Не удалось записать в сокет 3 [WiFiEsp] Отключение 3 , @Lennart Jansson