WebServer功能很多,最主要的一块就是解析来自用户的HTTP请求,然后根据功能需求将响应的消息发送给客户。这篇文章将粗略介绍ESPAsyncWebServer中HTTP通讯相关的请求和响应的处理。
本文中各例程演示均在ESP32中进行。
用户从浏览器输入网址或者通过其他程序等访问服务器的时候会向服务器发送消息,这就是HTTP请求,它的格式如下: 下面是个请求的示例: 请求即是用户希望服务器做的事,而服务器则解读该请求,然后进行响应,这里对ESPAsyncWebServer请求解析相关方法进行说明。
ESPAsyncWebServer中对于请求的调取实在回调函数中进行的,回调函数传入一个 AsyncWebServerRequest 对象,该对象就是用户的请求,我们可以通过该对象获取到很多信息,比如下面这些基础信息:
request->version(); // uint8_t: 0 = HTTP/1.0, 1 = HTTP/1.1 request->method(); // enum: HTTP_GET, HTTP_POST, HTTP_DELETE, HTTP_PUT, HTTP_PATCH, HTTP_HEAD, HTTP_OPTIONS // HTTP_GET = 0b00000001, HTTP_POST = 0b00000010, HTTP_DELETE = 0b00000100, HTTP_PU = 0b00001000, HTTP_PATCH = 0b00010000, HTTP_HEAD = 0b00100000, HTTP_OPTIONS = 0b01000000, HTTP_ANY = 0b01111111 request->url(); // String: URL of the request (not including host, port or GET parameters) request->host(); // String: The requested host (can be used for virtual hosting) request->contentType(); // String: ContentType of the request (not avaiable in Handler::canHandle) request->contentLength(); // size_t: ContentLength of the request (not avaiable in Handler::canHandle) request->multipart(); // bool: True if the request has content type "multipart"除了上面几个基础信息我们也可以通过遍历获取请求头中的所有信息:
int headers = request->headers(); int i; for(i=0;i<headers;i++){ AsyncWebHeader* h = request->getHeader(i); Serial.printf("HEADER[%s]: %s\n", h->name().c_str(), h->value().c_str()); // 下面行功能同上面两行 //Serial.printf("HEADER[%s]: %s\n", request->headerName(i).c_str(), request->header(i).c_str()); }我们也可以通过指定头部字段名来获取对应的值:
if(request->hasHeader("MyHeader")){ AsyncWebHeader* h = request->getHeader("MyHeader"); Serial.printf("MyHeader: %s\n", h->value().c_str()); // 下面行功能同上面两行 // Serial.printf("MyHeader: %s\n", request->header("MyHeader").c_str()); }除了上面内容外,请求中很多时候还会带入参数,比如GET方法中url中会有 ?key=value&key=value 这类字样的内容(问号后的就是参数,参数为键值对形式,不同参数间用&分隔),POST方法中参数通常放在请求数据中,参数可以用下面方式获取:
int params = request->params(); for(int i=0;i<params;i++){ AsyncWebParameter* p = request->getParam(i); if(p->isFile()){ //p->isPost() is also true Serial.printf("FILE[%s]: %s, size: %u\n", p->name().c_str(), p->value().c_str(), p->size()); } else if(p->isPost()){ Serial.printf("POST[%s]: %s\n", p->name().c_str(), p->value().c_str()); } else { //GET Serial.printf("GET[%s]: %s\n", p->name().c_str(), p->value().c_str()); } } // 下面语句功能同上面 //int args = request->args(); //for(int i=0;i<args;i++){ // Serial.printf("ARG[%s]: %s\n", request->argName(i).c_str(), request->arg(i).c_str()); //}我们也可以通过参数名来获取其对应的值:
if(request->hasParam("download")) //Check if GET parameter exists AsyncWebParameter* p = request->getParam("download"); if(request->hasParam("download", true)) //Check if POST (but not File) parameter exists AsyncWebParameter* p = request->getParam("download", true); if(request->hasParam("download", true, true)) //Check if FILE was uploaded AsyncWebParameter* p = request->getParam("download", true, true); // 下面语句功能同上面 //if(request->hasArg("download")) // String arg = request->arg("download");上面出现了POST方法中主体数据中带有文件或其它数据的情况,这些数据可以通过专门的回调函数来处理,详细用法可以参考我ESPAsyncWebServer系列文章中对于事件处理绑定的介绍。
除了上面这些形式的参数外ESPAsyncWebServer库还提供了解析路径参数(Path variable)的方法,可以参考项目官方文档中 Setting up the server > Path variable 章结内容。
和请求一样响应也有一定的格式: 下面是个响应的示例: 响应简单来说就是根据上面的格式向客户端发送消息,最简单比如下面这样(ESPAsyncWebServer会严重遵循格式,未提供的内容会自动补足):
// 只发送状态码 request->send(404); //Sends 404 File Not Found稍微增加点内容就变成下面这样:
// 发送状态码、报文主体数据类型、报文主题内容 request->send(200, "text/plain", "Hello World!");我们也可以从文件系统向用户发送文件(发送文件并不推荐这么做,因为ESPAsyncWebServer库中提供了更好的方式,会在后面单独介绍):
request->send(SPIFFS, "/index.htm"); //Send index.htm with default content type request->send(SPIFFS, "/index.htm", "text/plain"); //Send index.htm as text request->send(SPIFFS, "/index.htm", String(), true); //Download index.htm上面有的例子中我们向客户端发送了字符串,如果字符串比较长,那么在程序运行时会有不小的内存开销,这里可以用Arduino的特殊机制来处理:
// 下面用了PROGMEM修饰的字符串在用到时将直接从Flash读取,减轻对内存的开销 const char index_html[] PROGMEM = "..."; // large char array, tested with 14k request->send_P(200, "text/html", index_html);上面这些操作中没有在响应头中添加过内容,如果需要在响应头中添加内容可以使用AsyncWebServerResponse :
AsyncWebServerResponse *response = request->beginResponse(200, "text/plain", "Hello World!"); response->addHeader("Server","ESP Async Web Server"); request->send(response);AsyncWebServerResponse通样支持PROGMEM:
const char index_html[] PROGMEM = "..."; // large char array, tested with 14k AsyncWebServerResponse *response = request->beginResponse_P(200, "text/html", index_html); response->addHeader("Server","ESP Async Web Server"); request->send(response);直接使用 request->send() 可行的方式在用上AsyncWebServerResponse基本也都可行。除了这两类响应方式,还有别的方式可用,比如下面这个:
AsyncResponseStream *response = request->beginResponseStream("text/html"); // AsyncResponseStream支持print、printf等方式添加内容 response->print("Hello: "); response->print(request->client()->remoteIP()); request->send(response);上面的响应都是直接返回字符串或是文件,ESPAsyncWebServer中还提供了相对精细一些的返回方式——返回 json ,这也是非常常用的数据格式了,参考下面方式:
#include "AsyncJson.h" #include "ArduinoJson.h" //下面方式对4KB或以下内容支持较好 AsyncResponseStream *response = request->beginResponseStream("application/json"); DynamicJsonBuffer jsonBuffer; JsonObject &root = jsonBuffer.createObject(); root["heap"] = ESP.getFreeHeap(); root["ssid"] = WiFi.SSID(); root.printTo(*response); request->send(response); #include "AsyncJson.h" #include "ArduinoJson.h" //下面方式对4KB以上内容支持较好,比如可以到40KB AsyncJsonResponse * response = new AsyncJsonResponse(); response->addHeader("Server","ESP Async Web Server"); JsonObject& root = response->getRoot(); root["heap"] = ESP.getFreeHeap(); root["ssid"] = WiFi.SSID(); response->setLength(); request->send(response);ESPAsyncWebServer中对于json的处理用到了ArduinoJson,需要另外安装,其安装使用说明可以参考下面文章: 《C++ Json库ArduinoJson介绍及使用说明》
除了直接进行响应外服务器也可以告诉客户端去访问别的链接,这就是url重定向:
request->redirect("/login"); //to local url request->redirect("https://www.baidu.com/"); //to external urlurl重定向支持过滤器功能,比如下面方式:
String RedirectUrl = "http://"; if (ON_STA_FILTER(request)) { RedirectUrl += WiFi.localIP().toString(); } else { RedirectUrl += WiFi.softAPIP().toString(); } RedirectUrl += "/index.htm"; request->redirect(RedirectUrl);ESPAsyncWebServer请求与响应功能非常多,这是里只是挑选了一部分作为介绍,更多内容可以查看项目官方的文档和例程,或者我的其他ESPAsyncWebServer的文章: ESPAsyncWebServer项目地址:https://github.com/me-no-dev/ESPAsyncWebServer 《Arduino for ESP8266&ESP32适用库ESPAsyncWebServer:快速入门》 《Arduino for ESP8266&ESP32适用库ESPAsyncWebServer:事件处理绑定》 《Arduino for ESP8266&ESP32适用库ESPAsyncWebServer:请求与响应》 《Arduino for ESP8266&ESP32适用库ESPAsyncWebServer:静态文件和模板引擎》 《Arduino for ESP8266&ESP32适用库ESPAsyncWebServer:WebSocket和EventSource》
HTTP请求和响应更多说明可以参考下面链接: https://baijiahao.baidu.com/s?id=1662842929861521073