Edit for clarity
The main thing I'm asking for help is on the HTTP parameter in my client::SendPostRequest
function. I think the problem is likey with that for various reasons. I'm not familiar with HTTP and was wondering if someone who was familiar could see if it was wrong at a glance. I'm adding more code by request but was mainly looking for confirmation that the following line of code is correct or incorrect way to format an HTTP POST request with a parameter. I appreciate any help or ideas! If anyone me to provide any more info, let me know.
httpClient.addHeader("Content-Type", "application/x-www-form-urlencoded");
int httpCode = httpClient.POST("/?message=" + message);
I'm writing an application where ESP32's can talk to each other and act as clients and servers. I'm using HTTP to do this. The <HTTPClient.h> library is being used for the client and the <AsyncTCP.h> and <ESPAsyncWebserver.h> libraries are being used for the server. I believe my routes on the server are setup correctly since I modeled it after the simple server example in the <ESPAsyncWebserver.h> GitHub page.
https://github.com/me-no-dev/ESPAsyncWebServer/blob/master/examples/simple_server/simple_server.ino
But I beleive I'm not forming the POST message right with the parameter (with the client code). I'm new to HTTP communication so I think somthing is wrong. Here's my function that makes the POST request.
/*
Function: Try sending some info to a server
(url): The server's url
Returns: HTTP code representing sucess or an error
*/
String client::SendPostRequest(String url, String message)
{
Serial.println("Client Sending Post");
HTTPClient httpClient;
// Connect to server and try to send the message
httpClient.begin(url);
//int httpCode = httpClient.POST("/?message" + message);
httpClient.addHeader("Content-Type", "text/plain");
int httpCode = httpClient.POST("/?message=" + message);
String resultInfo;
if (httpCode > 0)
{
// Serial.println(httpClient.getString());
resultInfo = "Success, HTTP Response Code: " + (String)httpCode;
}
else
{
resultInfo = "Error, HTTP Response Code: " + (String)httpCode;
}
httpClient.end();
return resultInfo;
}
I've looked on several websites online, tried something from another stack overflow question, and tried using Chat GPT to trouble shoot this problem. I've upload my main sketch to two ESP32's (ESP32 #1 and ESP32 #2). ESP32 #1 makes a POST request to send "Testing Testing 1 2 3" to ESP32 #2. ESP32 #2 makes a GET request to ESP32 #1. The GET request works fine. For the POST request ESP32 #1 sends the post request and sees that a sucess code of 200 has been sent. ESP32 then runs the code that setup the POST route to that URL on its server. However ESP32 never prints the message. I think it is never printing it because my SendPostRequest code is not correct setting up the POST paraemter. The server code that sets up the POST route is below. My ESP32 #2 server prints "Server running post request" but the if (request->hasParam("message", true)) never evaluates to true. If it was working properly I'd expect to see "Server got post message = Testing Testing 1 2 3". Thanks in advance for any help or advice!
// Post request
webServer->on("/postTest", HTTP_POST, [](AsyncWebServerRequest *request)
{
Serial.println("Server running post request");
String message;
if (request->hasParam("message", true))
{
message = request->getParam("message", true)->value();
Serial.println("Server got post message = " + (String)message);
}
else
{
message = "No message sent";
}
request->send(200, "text/plain", "Hello, POST: " + message);
});
ESP32 #1 Serial Monitor Output:
Server running get request
ESP #1: Loop=4 | Success, HTTP Response Code: 200
Client Sending Post
Server running get request
ESP #1: Loop=5 | Success, HTTP Response Code: 200
Server running get request
Client Sending Post
ESP #1: Loop=6 | Success, HTTP Response Code: 200
Server running get request
Client Sending Post
Server running get request
ESP #1: Loop=7 | Success, HTTP Response Code: 200
ESP32 #2 Serial Monitor Output:
Client Sending GET
ESP #2: Loop=339 | Hello, world from ESP32
Server running post request **<-- I want to see "Server got post message = Testing Testing 1 2 3 after this line**
Client Sending GET
ESP #2: Loop=340 | Hello, world from ESP32
Server running post request
Client Sending GET
ESP #2: Loop=341 | Hello, world from ESP32
Server running post request
Client Sending GET
ESP #2: Loop=342 | Hello, world from ESP32
Client Sending GET
Server running post request
ESP #2: Loop=343 | Hello, world from ESP32
EDIT By request, I'm adding the full code that each ESP32 runs. Here's the main .ino sketch.
#include "client.h"
#include "device.h"
#include "menu.h"
#include "server.h"
#include "wifi.h"
unsigned long testCount;
bool isServer1 = false;
client oClient;
device oDevice;
menu oMenu;
server oServer;
wifi oWifi;
void setup()
{
testCount = 0;
Serial.begin(115200);
oMenu.InitalizeScreen();
int port;
String espName;
if(isServer1)
{
port = 80;
espName = "ESP32 #1";
Serial.println(espName);
oServer.SetPort(port);
}
else
{
espName = "ESP32 #2";
port = 10555;
Serial.println(espName);
oServer.SetPort(port);
}
// Try connecting to WiFi and start acting as a server for this room
oWifi.Connect();
oMenu.Connecting();
oServer.StartServer();
// Display networking information on the screen
oMenu.NetworkingInfo(espName, oWifi.GetIpAddress(), (String)port);
}
void loop()
{
if(oWifi.IsConnected())
{
String message;
if(isServer1)
{
//message = oClient.SendGetRequest("http://192.168.43.117:10555/"); // connect to 2 from 1
// Send some data to server 2 from server 1
message = oClient.SendPostRequest("http://192.168.43.117:10555/postTest", "Testing Testing 1 2 3");
//message = oClient.SendPostRequest("http://192.168.43.100:80/postTest", "Testing Testing 1 2 3");
}
else
{
message = oClient.SendGetRequest("http://192.168.43.100:80/"); // connect to 1 from 2
}
if(isServer1)
{
Serial.print("ESP #1: Loop=" + (String)testCount + " | ");
}
else
{
Serial.print("ESP #2: Loop=" + (String)testCount + " | ");
}
Serial.println(message);
}
delay(2000);
testCount = testCount + 1;
}
Here's the full .ino file for my server class.
#include "server.h"
/*
Function: Create the server listening on port 80 by default
*/
server::server()
{
server::port = 80;
}
/*
Function: Create the server listening on a specified port
(port): port number to listen on
*/
server::server(unsigned int port)
{
server::port = port;
}
/*
Function: Free memory for stuff allocated on heap
*/
server::~server()
{
delete server::webServer;
}
/*
Function: Create response for when the server is not found
(request): HTTP request to this server
*/
void server::NotFound(AsyncWebServerRequest *request)
{
request->send(404, "text/plain", "Not found");
}
/*
Function: Set the port to listen to
(port): port number to listen to
*/
void server::SetPort(unsigned int port)
{
server::port = port;
}
/*
Function: create responses for different HTTP requests
(webServer): This objects web server. Things sending HTTP request to it get these responses
*/
void server::SetupResponses(AsyncWebServer* webServer)
{
// Get request
webServer->on("/", HTTP_GET, [](AsyncWebServerRequest *request)
{
Serial.println("Server running get request");
request->send(200, "text/plain", "Hello, world from ESP32");
});
// Post request
webServer->on("/postTest", HTTP_POST, [](AsyncWebServerRequest *request)
{
Serial.println("Server running post request");
String message;
if (request->hasParam("message", true))
{
message = request->getParam("message", true)->value();
Serial.println("Server got post message = " + (String)message);
}
else
{
message = "No message sent";
}
request->send(200, "text/plain", "Hello, POST: " + message);
});
webServer->onNotFound(NotFound);
}
/*
Function: Start the server
*/
void server::StartServer()
{
server::webServer = new AsyncWebServer(server::port);
server::SetupResponses(webServer);
webServer->begin();
}
Here's the full .ino file for my client class.
#include "client.h"
/*
Function: Try to get information from a server
Returns: Returns the payload when successful. Returns an error message when it's not sucessful.
*/
String client::SendGetRequest(String url)
{
Serial.println("Client Sending GET");
HTTPClient httpClient;
String getMessage = "Error on HTTP GET request";
// Send get request to that URL
httpClient.begin(url);
int httpCode = httpClient.GET();
if (httpCode > 0)
{
getMessage = httpClient.getString();
}
else
{
getMessage = getMessage + " | Error Code: " + (String)httpCode;
}
httpClient.end();
return getMessage;
}
/*
Function: Try sending some info to a server
(url): The server's url
Returns: HTTP code representing sucess or an error
*/
String client::SendPostRequest(String url, String message)
{
Serial.println("Client Sending Post");
HTTPClient httpClient;
// Connect to server and try to send the message
httpClient.begin(url);
//int httpCode = httpClient.POST("/?message" + message);
// httpClient.addHeader("Content-Type", "text/plain");
httpClient.addHeader("Content-Type", "application/x-www-form-urlencoded");
int httpCode = httpClient.POST("/?message=" + message);
String resultInfo;
if (httpCode > 0)
{
// Serial.println(httpClient.getString());
resultInfo = "Success, HTTP Response Code: " + (String)httpCode;
}
else
{
resultInfo = "Error, HTTP Response Code: " + (String)httpCode;
}
httpClient.end();
return resultInfo;
}
In esp32 Arduino HTTPClient library, the parameter of httpClient.POST
is the body of the request. HTTP POST requests shouldn't have URL parameters.
With content-type "application/x-www-form-urlencoded" the esp32 Arduino WebServer will parse the body of the POST request as URL parameters so you will read the value of the parameter with request->getParam
.
To have a valid URL parameters string in the body of the POST request, remove the "/?" from httpClient.POST("/?message=" + message);