When I run a CuRL POST request to my Vercel app, I get a 200 response code. When I do the same thing with HTTPClient on my ESP32, I get a 308 Permanent Redirect, with the redirect URL being the same URL I requested, causing an infinite loop.
Curl request: curl -X POST https://soil-moisture-monitor-phi.vercel.app/api/updateMeasurement -H “Content-Type: application/json” -d ‘{“measurement”: 123.45}’
ESP32 code:
#include <WiFi.h>
#include <HTTPClient.h>
#include <LiquidCrystal_I2C.h>
#define SENSOR_INPUT 36//15
#define LIGHT_PORT 12
LiquidCrystal_I2C lcd(0x27,16,2);
const String ssid = "REDACTED";
const String password = "REDACTED";
const String serverName = "https://soil-moisture-monitor-phi.vercel.app/api/updateMeasurement/";
int prevHumidity = 0;
void setup() {
Serial.begin(9600);
pinMode(LIGHT_PORT, OUTPUT);
lcd.init();
lcd.clear();
lcd.backlight();
WiFi.begin(ssid, password);
while(WiFi.status() != WL_CONNECTED){
Serial.print("Connecting...");
delay(100);
}
Serial.println("Connected!");
// delay(1000);
pinMode(LIGHT_PORT, OUTPUT);
if(WiFi.status() == WL_CONNECTED){
WiFiClient client;
HTTPClient http;
// Your Domain name with URL path or IP address with path
http.begin(client, serverName);
const char* headerNames[] = { "Location", "Last-Modified" };
http.collectHeaders(headerNames, sizeof(headerNames)/sizeof(headerNames[0]));
// Data to send with HTTP POST
String payload = "{\"measurement\": "+String(12345) + "}";
// Authorization
// Send HTTP POST request
http.addHeader("Content-Type", "application/json");
http.setFollowRedirects(HTTPC_FORCE_FOLLOW_REDIRECTS);
int httpResponseCode = http.POST(payload);
Serial.print("HTTP Response code: ");
Serial.println(httpResponseCode);
if (httpResponseCode == 308) {
String location = http.header("Location"); // Get redirect target
http.end();
Serial.println("Redirected to: " + location);
// Try the new location
http.begin(client, location);
http.addHeader("Content-Type", "application/json");
httpResponseCode = http.POST(payload);
Serial.print("New code: ");
Serial.println(httpResponseCode);
}
// Free resources
http.end();
}
else {
Serial.println("WiFi Disconnected");
}
}
void loop() {
// put your main code here, to run repeatedly:
int sensorOutput = analogRead(SENSOR_INPUT);
int humidityPercentage = map(sensorOutput, 0, 4095, 100, 0);
if (humidityPercentage < 30) {
digitalWrite(LIGHT_PORT, HIGH);
} else {
digitalWrite(LIGHT_PORT, LOW);
}
prevHumidity = humidityPercentage;
lcd.setCursor(1,0);
lcd.print("Soil Humidity:");
lcd.setCursor(6,1);
lcd.print(String(humidityPercentage)+"%");
// When the probe is not in soil it reports moisture as 0 or 1%
// if (humidityPercentage != prevHumidity && humidityPercentage > 1){
// if(WiFi.status() == WL_CONNECTED){
// WiFiClient client;
// HTTPClient http;
// // Your Domain name with URL path or IP address with path
// http.begin(client, serverName);
// // Data to send with HTTP POST
// String httpRequestData = "";
// // Authorization
// // Send HTTP POST request
// http.addHeader("Content-Type", "application/json");
// int httpResponseCode = http.POST("{\"measurement\": "+String(humidityPercentage) + "}");
// Serial.print("HTTP Response code: ");
// Serial.println(httpResponseCode);
// // Free resources
// http.end();
// }
// else {
// Serial.println("WiFi Disconnected");
// }
// }
if (humidityPercentage < 30) {
digitalWrite(LIGHT_PORT, HIGH);
} else {
digitalWrite(LIGHT_PORT, LOW);
}
prevHumidity = humidityPercentage;
}
My webapp code is here: GitHub - sr5434/soil-moisture-monitor
anshumanb
(Anshuman Bhardwaj)
May 5, 2025, 4:28am
2
Hi @samirrangwalla-gmail , welcome to the Vercel Community!
Sorry that you’re facing this issue. In your code, I see you have a trailing slash /
in the URL. Can you try removing that and then checking if the issue exists?
Removing the trailing slash does not change anything. I noticed that in the logs on my ESP32 it said that it received an HTTP 1.0 response but in CuRL it said it was running HTTP 2.0. Could that be the reason why I am getting redirected?
anshumanb
(Anshuman Bhardwaj)
May 6, 2025, 5:59am
4
Hi @samirrangwalla-gmail , all traffic from Vercel is served by h2. Are you using some VPN or firewall software on your computer or the local network? I’ve noticed in the past that such programs can affect the outcome in some rare cases.
No, I’m not using a vpn or firewall.
anshumanb
(Anshuman Bhardwaj)
May 7, 2025, 4:47am
6
I see. Can you share the response you get in your ESP32 code? I mean the response headers and status code. That’ll help us narrow down.
Can you also share the updated copy of the ESP32 code?
I am getting a 308 response code. Below are the response headers:
Header Name: Location
Header Value: https://soil-moisture-monitor-phi.vercel.app/api/updateMeasurement
Header Name: Last-Modified
Header Value:
Below is my updated code:
#include <WiFi.h>
#include <HTTPClient.h>
#include <LiquidCrystal_I2C.h>
#include <esp_log.h>
#define SENSOR_INPUT 36//15
#define LIGHT_PORT 12
LiquidCrystal_I2C lcd(0x27,16,2);
const String ssid = "REDACTED";
const String password = "REDACTED";
const String serverName = "https://soil-moisture-monitor-phi.vercel.app/api/updateMeasurement";
int prevHumidity = 0;
void setup() {
Serial.begin(9600);
esp_log_level_set("*", ESP_LOG_VERBOSE);
pinMode(LIGHT_PORT, OUTPUT);
lcd.init();
lcd.clear();
lcd.backlight();
WiFi.begin(ssid, password);
while(WiFi.status() != WL_CONNECTED){
Serial.print("Connecting...");
delay(100);
}
Serial.println("Connected!");
// delay(1000);
pinMode(LIGHT_PORT, OUTPUT);
if(WiFi.status() == WL_CONNECTED){
WiFiClient client;
HTTPClient http;
// Your Domain name with URL path or IP address with path
http.begin(client, serverName);
const char* headerNames[] = { "Location", "Last-Modified" };
http.collectHeaders(headerNames, sizeof(headerNames)/sizeof(headerNames[0]));
// Data to send with HTTP POST
String payload = "{\"measurement\": "+String(12345) + "}";
// Authorization
// Send HTTP POST request
http.addHeader("Content-Type", "application/json");
http.setFollowRedirects(HTTPC_FORCE_FOLLOW_REDIRECTS);
int httpResponseCode = http.POST(payload);
Serial.print("HTTP Response code: ");
Serial.println(httpResponseCode);
int headerCount = http.headers();
Serial.printf("Header count: %d\n", headerCount);
for (int i = 0; i < headerCount; i++) {
Serial.printf("Header Name: %s\n", http.headerName(i).c_str());
Serial.printf("Header Value: %s\n", http.header(i).c_str());
}
if (httpResponseCode == 308) {
String location = http.header("Location"); // Get redirect target
http.end();
Serial.println("Redirected to: " + location);
// Try the new location
http.begin(client, location);
const char* headerNames[] = { "Location", "Last-Modified" };
http.collectHeaders(headerNames, sizeof(headerNames)/sizeof(headerNames[0]));
http.addHeader("Content-Type", "application/json");
httpResponseCode = http.POST(payload);
Serial.print("New code: ");
Serial.println(httpResponseCode);
int headerCount = http.headers();
Serial.printf("Header count: %d\n", headerCount);
for (int i = 0; i < headerCount; i++) {
Serial.printf("Header Name: %s\n", http.headerName(i).c_str());
Serial.printf("Header Value: %s\n", http.header(i).c_str());
}
}
// Free resources
http.end();
}
else {
Serial.println("WiFi Disconnected");
}
}
void loop() {}```
anshumanb
(Anshuman Bhardwaj)
May 8, 2025, 5:43am
8
Hi @samirrangwalla-gmail , thanks for sharing additional details. I think the issue/limitation lies into the HTTP Client we’re using here because Vercel responses are be same as reflected by cURL.
Are there alternative HTTP client that you can use for your program? Maybe just for testing purpose to see what could be the actual issue.
I found some relevant posts:
It seems that the tutorials you sent are out of date, as they require libraries that are no longer available.
anshumanb
(Anshuman Bhardwaj)
May 9, 2025, 12:07pm
10
Oh, I see. I’d suggest to look up for alternatives and share if the problem persists. Because this is hard to reproduce without the same codebase/hardware client.