HTTP-запрос ESP32 обрабатывает ответ веб-сервера Go, но не работает на JS-серверах node.
Я настроил плату esp32 (wemos d1 r32) для отправки запроса на сервер, размещенный в моей локальной сети. Если я настрою очень простой сервер go, плата отлично обработает ответ (200 с соответствующим содержимым тела). Когда я переключаюсь на сервер Node JS, он отвечает только кодом состояния 400
. Самое странное, что ни один из вызовов console.log
в обработчиках маршрутов не вызывается, что указывает на то, что он завершает работу еще до того, как доберется до экспресс-сервера. Я проверил, что сервер возвращает тело & код состояния Я хочу использовать почтальона, все выглядит хорошо.
Я пробовал разные фреймворки (Koa), чтобы понять, связано ли это с Express, но и с ним это не работает. Я предполагаю, что это как-то связано с NodeJS?
Экспресс-сервер
import express from "express";
const app = express();
app.use(express.json());
app.post("/", (req, res) => {
console.log(req.body);
req.statusCode = 200;
res.send("200");
});
app.get("/hello", (req, res) => {
res.setTimeout(50000);
console.log(req.body);
res.setHeader("Location", "123");
res.setHeader("Server", "123");
req.statusCode = 200;
res.send("200");
});
app.listen(8090, () => {
console.log(`Example app listening on port ${8090}`);
});
Сервер Go
package main
import (
"fmt"
"net/http"
)
func hello(w http.ResponseWriter, req *http.Request) {
for name, headers := range w.Header() {
for _, h := range headers {
fmt.Fprintf(w, "%v: %v\n", name, h)
}
}
fmt.Fprintf(w, "hello\n")
}
func headers(w http.ResponseWriter, req *http.Request) {
for name, headers := range req.Header {
for _, h := range headers {
fmt.Fprintf(w, "%v: %v\n", name, h)
}
}
}
func main() {
fmt.Println("?")
http.HandleFunc("/hello", hello)
http.HandleFunc("/headers", headers)
http.ListenAndServe(":8090", nil)
}
Скрипт Arduino
#include <HTTPClient.h>
#include <WiFi.h>
// #define LOG_LOCAL_LEVEL ESP_LOG_VERBOSE
#include "esp_log.h"
const char* ssid = "xxx";
const char* password = "xxx";
String webserver = "http://192.168.0.19:8090/hello";
String qrCode;
void WiFiStationConnected(WiFiEvent_t event, WiFiEventInfo_t info){
Serial.println("Connected to AP successfully!");
}
void WiFiGotIP(WiFiEvent_t event, WiFiEventInfo_t info){
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
}
void WiFiStationDisconnected(WiFiEvent_t event, WiFiEventInfo_t info){
WiFi.disconnect(true);
delay(1000);
WiFi.mode(WIFI_STA);
delay(1000);
Serial.println("Disconnected from WiFi access point");
Serial.print("WiFi lost connection. Reason: ");
Serial.println(info.disconnected.reason);
Serial.println("Trying to Reconnect");
WiFi.begin(ssid, password);
delay(5000);
}
void setup() {
esp_log_level_set("*", ESP_LOG_VERBOSE);
Serial.begin(9600);
Serial2.begin(9600);
Serial.println("Hello, ESP32!");
Serial.println(WiFi.getMode());
Serial.println(WiFi.macAddress());
WiFi.onEvent(WiFiStationConnected, WiFiEvent_t::SYSTEM_EVENT_STA_CONNECTED);
WiFi.onEvent(WiFiGotIP, WiFiEvent_t::SYSTEM_EVENT_STA_GOT_IP);
WiFi.onEvent(WiFiStationDisconnected, WiFiEvent_t::SYSTEM_EVENT_STA_DISCONNECTED);
WiFi.begin(ssid, password);
}
int cnt = 0;
void loop() {
while (Serial2.available()) {
int ch = Serial2.read();
char character = ch;
Serial.print(ch);
// end char
if(character == 13){
Serial.print("\n");
Serial.println(qrCode);
Serial.println(cnt);
qrCode = "";
cnt = 0;
send(qrCode);
} else {
cnt = ch + cnt;
qrCode = qrCode + character;
}
}
}
void tryWifi() {
WiFi.begin(ssid, password);
int status = WiFi.status();
while (status == 6 || status == 4 || status == 5 || status == 1) {
Serial.print("Failed to connect:");
Serial.print(status);
Serial.print("\n");
delay(1500);
WiFi.begin(ssid, password);
}
}
void send(String json) {
HTTPClient http;
if(http.begin(webserver)){
int httpCode = http.GET();
http.addHeader("Content-Type", "application/json");
http.addHeader("Host", "something");
// client.print("Content-Length: ");
delay(1500);
Serial.println(httpCode);
Serial.println(http.getString());
if (httpCode > 0) {
Serial.printf("[HTTP] GET... code: %d\n", httpCode);
if(httpCode == HTTP_CODE_OK || httpCode == HTTP_CODE_MOVED_PERMANENTLY) {
String payload = http.getString();
if (payload != "false"){
Serial.println(payload);
delay(1500);
} else {
Serial.println("Bad Playload");
}
} else {
}
} else {
Serial.println("Error sending to HTTP");
}
http.end();
} else {
Serial.println("?");
}
}
@Batzz, 👍1
2 ответа
Ваш код Arduino выглядит следующим образом:
int httpCode = http.GET();
http.addHeader("Content-Type", "application/json");
http.addHeader("Host", "something");
// client.print("Content-Length: ");
delay(1500);
Serial.println(httpCode);
Serial.println(http.getString());
if (httpCode > 0) {
Вызов http.GET()
фактически выполняет HTTP-запрос. Вы добавляете заголовки после выполнения запроса. Их нужно добавить перед ним. Таким образом, ваш код должен выглядеть так:
// http.addHeader("Content-Type", "application/json");
int httpCode = http.GET();
// delay(1500); -- здесь не нужно вызывать delay()
Serial.println(httpCode);
Serial.println(http.getString());
if (httpCode > 0) {
Код состояния HTTP 400 означает "неверный запрос". Некоторые веб-серверы возвращают этот код, если заголовки, которые они ожидают увидеть, отсутствуют или имеют бессмысленные значения. Веб-серверы Go и Javascript имеют разные реализации и могут по-разному вести себя с некорректно сформированными запросами.
Я удалил "Хост" заголовок, поскольку HTTPClient
делает это за вас . И нет необходимости в вызове delay()
после вызова http.GET()
.
Обновлено: я также закомментировал "Content-Type" заголовок, так как это не имеет смысла в запросе GET, спасибо @EdgarBonet за упоминание об этом. Я оставляю его в качестве комментария, чтобы было ясно, что любые заголовки должны быть добавлены до выполнения запроса.
По прошествии неоправданного времени я понял, что запрос завершается с ошибкой 400, поскольку в конце URL-адреса нет косой черты (http://192.168.1.208:8090
-> http://192.168.1.208:8090/
). Это должно быть что-то конкретное для NodeJS, так как это нормально работает на сервере go.
- HTTP POST от Arduino/ESP8266/ESP32 Как отправлять параметры (x-www-form-urlencoded)
- AsyncWebServer дает сброс wdt
- Точка доступа ESP32 и веб сервер HTTP, как отправить несколько параметров?
- esp32 http client response только 200 не получил данные после этого
- EspAsyncWebServer обрабатывает HTTPS в HTTP
- Использование ESPAsyncWebServer.h с ArduinoJson версии 6 для транзакций мастер-клиент
- ArduinoHTTPClient POST multipart/form-data с SD-карты, возвращающий 400 неверных запросов
- HTTPS GET request работает на esp32 но не на esp8266
Также обратите внимание, что
"Content-Type"
не имеет смысла в HTTP-запросе. OP, вероятно, означает «Принять»., @Edgar Bonet@EdgarBonet Спасибо, хорошая мысль. На самом деле это имеет смысл для запросов PUT или POST, у которых есть тело, но не для GET, у которых никогда не должно быть тела. Я отредактировал ответ. Я подозреваю, что ОП просто добавлял случайные строки кода, чтобы посмотреть, исправили ли они свою проблему., @romkey
Спасибо за комментарии. У меня был заголовок
Content-Type
, так как я намеревался использовать запрос POST с телом json. Я переместил вызов, чтобы установить заголовок до того, как запрос будет запущен, хороший улов!, @Batzz