问题
I'm writing a simple HTTP webserver on my Arduino Uno Wifi Rev2 to handle an incoming HTTP POST Request in JSON format.
This is how I'm sending the HTTP request (with JSON) from my client:
curl \
--request POST \
--header "Content-Type: application/json" \
--data '{
"A": "B",
"C": "D"
}' \
"http://192.168.4.1/myEndpoint"
This is the string the Arduino web-server receives:
POST /myEndpoint HTTP/1.1\r\nHost: 192.168.4.1\r\nUser-Agent: curl/7.54.0\r\nAccept: */*\r\nContent-Type: application/json\r\nContent-Length: 34\r\n\r\n{\n "A": "B",\n "C": "D" \n}
I'm using Nick Gammon's Arduino Regexp library to parse this request, validate it and extract the JSON data.
This works, but parsing the HTTP request in this way is extremely brittle and feels hacky. It could easily break if a different client re-orders/omits a header or skips the carriage return characters. This is the god-awful regexp I'm using for validation:
httpRegexp = "POST /myEndpoint HTTP/[%d%.]+%\r%\nHost: 192%.168%.4%.1%\r%\nUser%-Agent: curl/[%d%.]+%\r%\nAccept: %*/%*%\r%\nContent%-Type: application/json%\r%\nContent%-Length: %d+%\r%\n%\r%\n{%s*\"[A-Za-z]+\"%s*:%s*\".+\"%s*,%s*\"[A-Za-z]+\"%s*:%s*\".+\"%s*}";
Is there a better/recommended way for me to validate and parse the HTTP request? This must be a problem that others have already encountered and solved. Please post a code fragment solving this issue if possible.
回答1:
As a starter:
First send a correct (syntax!) test request
curl \
request POST \
header "Content-Type:application/json" \
data '{"A":"B","C":"D"}' \
"http://192.168.4.1/myEndpoint"
there are tons of excellent examples if you do a search for :
arduino webserver ethernet library
on your favorite search enginne.
One would be: https://startingelectronics.org/tutorials/arduino/ethernet-shield-web-server-tutorial/
or you use the webserver library from esp8266 and adapt it (not really hard imho)
you would do on the Arduino something like
webServer.on("/myroute/lighton", HTTP_POST, readJson);
char jsonField[64] = '\0'; //This is a predefined buffer for data handilng
the function would look like (partly working code, partly pseudo code )
bool readJson(){
if (webserver.args() == 0) return false; // we could do in the caller an error handling on that
strcpy (jsonField, webserver.arg(1).c_str()); // here we copy the json to a buffer
/** Get rid of starting and finishing bracket and copy to */
strncpy(jsonField , jsonField + 1, strlen(jsonField) - 2);
jsonField[strlen(jsonField) - 2] = '\0';
uint16_t maxIndex = strlen(jsonField); // number of characters received - without the brackets
uint16_t index = 0;
int16_t nextIndex = 0;
uint8_t i = 0;
// In this routine we get the value pairs e.g. "A":"B"
while ((nextIndex != -1) && (nextIndex < maxIndex)) {
nextIndex = indexOf(jsonField, ',', index);
... the next step would be to process the value pairs by stripping the " and split on the ':' delimiter --
if you need just the values = content in your example B and D its easy,
you could do
if (strcmp (firstValofPair ,'A')==0) valueB = atoi(B); // given B is a number and we have to convert from char to int
.... some more logic and you have a simple reliable JSON Parser for all kind of web server usage
}
return true; // success parsing
}
I have implemented this kind of logic in some real live scenarios and all work reliable and stable for some years now. A final tip:
Never use the Arduino String class in Arduino webserver scenarios. The String class fractures your heap and crashes your Arduino. In my example I use fixed chars which are compiled to the stack and keeps your memory happy.
回答2:
The linked Regexp library is based on Lua, which has an interesting pattern match operator
%b() balanced nested pair ( ... ( ... ) ... )
Then to capture a balanced curly brace expression at the end of the HTTP request, use the expression
"(%b{})%s*$"
As pointed out in the comments, this doesn't mean the capture is valid JSON. The next step would be to pass the captured substring to a JSON parser for validation.
来源:https://stackoverflow.com/questions/60862963/best-way-to-parse-out-incoming-http-post-request-on-arduino