帮酷LOGO
  • 显示原文与译文双语对照的内容
Async Web Server for ESP8266 Arduino

  • 源代码名称:ESPAsyncWebServer
  • 源代码网址:http://www.github.com/me-no-dev/ESPAsyncWebServer
  • ESPAsyncWebServer源代码文档
  • ESPAsyncWebServer源代码下载
  • Git URL:
    git://www.github.com/me-no-dev/ESPAsyncWebServer.git
  • Git Clone代码到本地:
    git clone http://www.github.com/me-no-dev/ESPAsyncWebServer
  • Subversion代码到本地:
    $ svn co --depth empty http://www.github.com/me-no-dev/ESPAsyncWebServer
    Checked out revision 1.
    $ cd repo
    $ svn up trunk
  • ESPAsyncWebServer Build Status

    帮助和支持 Join the chat at https://gitter.im/me-no-dev/ESPAsyncWebServer

    用于 ESP8266 Arduino的异步HTTP和 web socket服务器

    对于 ESP8266,它需要 ESPAsyncTCP 使用这个库,你可能需要有最新的git版本( Arduino内核)

    对于 ESP32,它需要 AsyncTCP 使用这个库,你可能需要使用最新版本的 ESP32.

    目录

    安装

    使用 PlatformIO

    是一个开放源码的生态系统,具有跨平台构建系统。库管理器和对 Espressif esp8266/esp32开发的全面支持的。 它在流行的主机操作系统上工作: Mac OS X,Windows,Linux 32/64, Linux ARM ( 像 树莓派,BeagleBone,CubieBoard ) 。

    • 安装 PlatformIO IDE
    • 使用platformio家庭> 新项目创建新项目"
    • 将 dev/platform更新为登台版本:
    [env:myboard]platform = espressif...board =.. .framework = arduino# using the latest stable versionlib_deps = ESP Async WebServer# or using GIT Url (the latest development version)lib_deps = https://github.com/me-no-dev/ESPAsyncWebServer.git
    • 使用PlatformIO进行愉快编码 !

    你为什么要

    • 使用异步网络意味着你可以同时处理多个连接
    • 当请求就绪并解析后,将调用你
    • 发送响应时,当服务器在后台发送响应时,你马上就可以处理其他连接了
    • 速度是 OMG
    • 易于使用的API,HTTP基本和摘要MD5认证( 默认值),ChunkedResponse
    • 易于扩展,可以处理任何类型的内容
    • 支持继续 100
    • 提供不同位置的异步 web socket插件,无需额外的服务器或者端口
    • 将事件发送到浏览器的异步 EventSource ( 服务器发送的事件) 插件
    • 用于条件和永久url重写的URL重写 插件
    • 支持缓存,最后修改,默认索引和更多的ServeStatic插件
    • 简单的模板处理引擎来处理模板

    重要的事情

    • 这是完全异步服务器,因此不在循环线程上运行。
    • 你不能使用yield或者延迟或者任何在回调中使用它们的函数
    • 服务器足够聪明,可以知道什么时候关闭连接和空闲资源
    • 你不能向单个请求发送多个响应

    工作原理

    异步网络服务器

    • 监听连接
    • 将新客户端包装到 Request
    • 跟踪客户并清理内存
    • 管理 Rewrites 并在请求url上应用它们
    • 管理 Handlers 并将它们附加到请求

    请求生命周期

    • TCP连接由服务器接收
    • 连接被封装在 Request 对象内
    • 收到请求头后,服务器将通过所有 Rewrites ( 按照他们被添加的顺序) 重写url并插入查询参数,接下来,通过所有附加的Handlers ( 按照他们被添加的顺序) 尝试查找一个指向给定请求的url 。 如果没有找到,则附加 default(catch-all) 处理程序。
    • 接收请求的它的余部分,如果需要( post+file/正文),则调用 HandlerhandleUpload 或者 handleBody 方法。
    • 在解析整个请求时,结果被给出 HandlerhandleRequest 方法,并准备好响应
    • handleRequest 方法中,Request 附加了一个 Response 对象( 请参见下面),它将响应数据返回给客户机
    • 发送 Response 时,客户端被关闭,并从内存中释放

    重写以及它们如何工作

    • Rewrites 用于重写请求url和/或者为特定请求url路径注入获取参数。
    • 按请求添加到服务器上的顺序对所有 Rewrites 进行评估。
    • 只有当请求 url ( 。排除获取参数) 完全 MATCH,并且可选的Filter 回调 return true 为时,Rewrite 才会更改请求 url 。
    • Filter 设置为 Rewrite 可以以控制何时应用重写,决策可以以基于请求 url 。http版本。请求 host/port/target 主机或者remoteIP请求 localIP 。
    • 提供了两个筛选回调: 当请求对AP接口执行重写时,ON_AP_FILTER 执行重写,ON_STA_FILTER 在请求STA接口时执行重写。
    • Rewrite 可以指定带有可选获取参数的目标 url,比如 /to-url?with=params

    处理程序及其工作原理

    • Handlers 用于执行特定请求的特定操作
    • 一个 Handler 实例可以附加到任何请求,并与服务器一起使用
    • 在服务器的设置上,可以控制什么时候应用处理程序,决定基于请求 url,http版本,请求 host/port/target 主机,获取参数或者客户机或者remoteIP请求 localIP 。
    • 提供了两个筛选回调: 当请求对AP接口执行重写时,ON_AP_FILTER 执行重写,ON_STA_FILTER 在请求STA接口时执行重写。
    • 在处理请求是否可以处理和声明 Request 应该解析的任何有趣标题时,canHandle 方法用于处理程序特定的控制。 决策可以基于请求方法。请求 url 。http版本。请求 host/port/target 主机和获取参数
    • 在给定 Handler/数据之后,一旦被完全解析并附加了 Response,它就会被附加到给定的Request ( canHandle 返回 true ) 上,并将它的附加到一个上。
    • 按它的附加到服务器的顺序对 Handlers 进行评估。 仅当设置为 Handler return true的Filter 才调用 canHandle
    • 可以选择能够处理请求的第一个 Handler,而不是调用 FiltercanHandle

    响应及其工作方式

    • Response 对象用于将响应数据发送回客户端
    • Response 对象与 Request 一起使用,在结束或者断开连接时释放
    • 根据响应类型使用不同的技术,发送几乎立即返回的数据包并发送下一个包。 任何时间之间的时间都用于运行用户循环并处理其他网络数据包
    • 异步响应可能是最难理解的事情
    • 用户可以使用许多不同的选项来响应后台任务

    模板处理

    • ESPAsyncWebserver包含简单的模板处理引擎。
    • 模板处理可以添加到大多数响应类型中。
    • 目前它只支持用实际值替换模板占位符。 无条件处理。循环等。
    • 占位符使用 % 符号分隔。 像这样:%TEMPLATE_PLACEHOLDER%
    • 它通过从响应文本提取占位符 NAME 并传递给提供的函数( 应该返回实际值返回实际值而不是占位符) 来工作。
    • 由于用户提供了功能,库用户可以实现条件处理和循环。
    • 由于事先不可能知道模板处理步骤之后的实际响应大小,所以响应变成了块 。

    使用AsyncWebServer的库和项目

    请求变量

    公共变量

    request->version(); // uint8_t: 0 = HTTP/1.0, 1 = HTTP/1.1request->method(); // enum: HTTP_GET, HTTP_POST, HTTP_DELETE, HTTP_PUT, HTTP_PATCH, HTTP_HEAD, HTTP_OPTIONSrequest->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"

    //List all collected headersint headers = request->headers();int i;for(i=0;i<headers;i++){
     AsyncWebHeader* h = request->getHeader(i);
     Serial.printf("HEADER[%s]: %sn", h->name().c_str(), h->value().c_str());
    }//get specific header by nameif(request->hasHeader("MyHeader")){
     AsyncWebHeader* h = request->getHeader("MyHeader");
     Serial.printf("MyHeader: %sn", h->value().c_str());
    }//List all collected headers (Compatibility)int headers = request->headers();int i;for(i=0;i<headers;i++){
     Serial.printf("HEADER[%s]: %sn", request->headerName(i).c_str(), request->header(i).c_str());
    }//get specific header by name (Compatibility)if(request->hasHeader("MyHeader")){
     Serial.printf("MyHeader: %sn", request->header("MyHeader").c_str());
    }

    ,POST和文件参数

    //List all parametersint 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: %un", p->name().c_str(), p->value().c_str(), p->size());
     } elseif(p->isPost()){
     Serial.printf("POST[%s]: %sn", p->name().c_str(), p->value().c_str());
     } else {
     Serial.printf("GET[%s]: %sn", p->name().c_str(), p->value().c_str());
     }
    }//Check if GET parameter existsif(request->hasParam("download"))
     AsyncWebParameter* p = request->getParam("download");//Check if POST (but not File) parameter existsif(request->hasParam("download", true))
     AsyncWebParameter* p = request->getParam("download", true);//Check if FILE was uploadedif(request->hasParam("download", true, true))
     AsyncWebParameter* p = request->getParam("download", true, true);//List all parameters (Compatibility)int args = request->args();for(int i=0;i<args;i++){
     Serial.printf("ARG[%s]: %sn", request->argName(i).c_str(), request->arg(i).c_str());
    }//Check if parameter exists (Compatibility)if(request->hasArg("download"))
     String arg = request->arg("download");

    文件上传处理

    voidhandleUpload(AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final){
     if(!index){
     Serial.printf("UploadStart: %sn", filename.c_str());
     }
     for(size_t i=0; i<len; i++){
     Serial.write(data[i]);
     }
     if(final){
     Serial.printf("UploadEnd: %s, %u Bn", filename.c_str(), index+len);
     }
    }

    体数据句柄

    voidhandleBody(AsyncWebServerRequest *request, uint8_t *data, size_t len, size_t index, size_t total){
     if(!index){
     Serial.printf("BodyStart: %u Bn", total);
     }
     for(size_t i=0; i<len; i++){
     Serial.write(data[i]);
     }
     if(index + len == total){
     Serial.printf("BodyEnd: %u Bn", total);
     }
    }

    响应

    重定向到另一个 URL

    //to local urlrequest->redirect("/login");//to external urlrequest->redirect("http://esp8266.com");

    使用HTTP代码的基本响应

    request->send(404); //Sends 404 File Not Found

    使用HTTP代码和附加标头的基本响应

    AsyncWebServerResponse *response = request->beginResponse(404); //Sends 404 File Not Foundresponse->addHeader("Server","ESP Async Web Server");
    request->send(response);

    字符串内容的基本响应

    request->send(200, "text/plain", "Hello World!");

    包含字符串内容和附加标题的基本响应

    AsyncWebServerResponse *response = request->beginResponse(200, "text/plain", "Hello World!");
    response->addHeader("Server","ESP Async Web Server");
    request->send(response);

    从PROGMEM发送大型网页

    constchar index_html[] PROGMEM = "..."; // large char array, tested with 14krequest->send_P(200, "text/html", index_html);

    从PROGMEM发送大型网页和附加标题

    constchar index_html[] PROGMEM = "..."; // large char array, tested with 14kAsyncWebServerResponse *response = request->beginResponse_P(200, "text/html", index_html);
    response->addHeader("Server","ESP Async Web Server");
    request->send(response);

    从包含模板的PROGMEM发送大型网页

    String processor(const String& var)
    {
     if(var == "HELLO_FROM_TEMPLATE")
     returnF("Hello world!");
     returnString();
    }//.. .constchar index_html[] PROGMEM = "..."; // large char array, tested with 14krequest->send_P(200, "text/html", index_html, processor);

    从包含模板和附加标题的PROGMEM发送大型网页

    String processor(const String& var)
    {
     if(var == "HELLO_FROM_TEMPLATE")
     returnF("Hello world!");
     returnString();
    }//.. .constchar index_html[] PROGMEM = "..."; // large char array, tested with 14kAsyncWebServerResponse *response = request->beginResponse_P(200, "text/html", index_html, processor);
    response->addHeader("Server","ESP Async Web Server");
    request->send(response);

    从PROGMEM发送二进制内容

    //File: favicon.ico.gz, Size: 726#definefavicon_ico_gz_len726constuint8_t favicon_ico_gz[] PROGMEM = {
     0x1F, 0x8B, 0x08, 0x08, 0x0B, 0x87, 0x90, 0x57, 0x00, 0x03, 0x66, 0x61, 0x76, 0x69, 0x63, 0x6F,
     0x6E, 0x2E, 0x69, 0x63, 0x6F, 0x00, 0xCD, 0x53, 0x5F, 0x48, 0x9A, 0x51, 0x14, 0xBF, 0x62, 0x6D,
     0x86, 0x96, 0xA9, 0x64, 0xD3, 0xFE, 0xA8, 0x99, 0x65, 0x1A, 0xB4, 0x8A, 0xA8, 0x51, 0x54, 0x23,
     0xA8, 0x11, 0x49, 0x51, 0x8A, 0x34, 0x62, 0x93, 0x85, 0x31, 0x58, 0x44, 0x12, 0x45, 0x2D, 0x58,
     0xF5, 0x52, 0x41, 0x10, 0x23, 0x82, 0xA0, 0x20, 0x98, 0x2F, 0xC1, 0x26, 0xED, 0xA1, 0x20, 0x89,
     0x04, 0xD7, 0x83, 0x58, 0x20, 0x28, 0x04, 0xAB, 0xD1, 0x9B, 0x8C, 0xE5, 0xC3, 0x60, 0x32, 0x64,
     0x0E, 0x56, 0xBF, 0x9D, 0xEF, 0xF6, 0x30, 0x82, 0xED, 0xAD, 0x87, 0xDD, 0x8F, 0xF3, 0xDD, 0x8F,
     0x73, 0xCF, 0xEF, 0x9C, 0xDF, 0x39, 0xBF, 0xFB, 0x31, 0x26, 0xA2, 0x27, 0x37, 0x97, 0xD1, 0x5B,
     0xCF, 0x9E, 0x67, 0x30, 0xA6, 0x66, 0x8C, 0x99, 0xC9, 0xC8, 0x45, 0x9E, 0x6B, 0x3F, 0x5F, 0x74,
     0xA6, 0x94, 0x5E, 0xDB, 0xFF, 0xB2, 0xE6, 0xE7, 0xE7, 0xF9, 0xDE, 0xD6, 0xD6, 0x96, 0xDB, 0xD8,
     0xD8, 0x78, 0xBF, 0xA1, 0xA1, 0xC1, 0xDA, 0xDC, 0xDC, 0x2C, 0xEB, 0xED, 0xED, 0x15, 0x9B, 0xCD,
     0xE6, 0x4A, 0x83, 0xC1, 0xE0, 0x2E, 0x29, 0x29, 0x99, 0xD6, 0x6A, 0xB5, 0x4F, 0x75, 0x3A, 0x9D,
     0x61, 0x75, 0x75, 0x95, 0xB5, 0xB7, 0xB7, 0xDF, 0xC8, 0xD1, 0xD4, 0xD4, 0xF4, 0xB0, 0xBA, 0xBA,
     0xFA, 0x83, 0xD5, 0x6A, 0xFD, 0x5A, 0x5E, 0x5E, 0x9E, 0x28, 0x2D, 0x2D, 0x0D, 0x10, 0xC6, 0x4B,
     0x98, 0x78, 0x5E, 0x5E, 0xDE, 0x95, 0x42, 0xA1, 0x40, 0x4E, 0x4E, 0xCE, 0x65, 0x76, 0x76, 0xF6,
     0x47, 0xB5, 0x5A, 0x6D, 0x4F, 0x26, 0x93, 0xA2, 0xD6, 0xD6, 0x56, 0x8E, 0x6D, 0x69, 0x69, 0xD1,
     0x11, 0x36, 0x62, 0xB1, 0x58, 0x60, 0x32, 0x99, 0xA0, 0xD7, 0xEB, 0x51, 0x58, 0x58, 0x88, 0xFC,
     0xFC, 0x7C, 0x10, 0x16, 0x02, 0x56, 0x2E, 0x97, 0x43, 0x2A, 0x95, 0x42, 0x2C, 0x16, 0x23, 0x33,
     0x33, 0x33, 0xAE, 0x52, 0xA9, 0x1E, 0x64, 0x65, 0x65, 0x71, 0x7C, 0x7D, 0x7D, 0xBD, 0x93, 0xEA,
     0xFE, 0x30, 0x1A, 0x8D, 0xE8, 0xEC, 0xEC, 0xC4, 0xE2, 0xE2, 0x22, 0x6A, 0x6A, 0x6A, 0x40, 0x39,
     0x41, 0xB5, 0x38, 0x4E, 0xC8, 0x33, 0x3C, 0x3C, 0x0C, 0x87, 0xC3, 0xC1, 0x6B, 0x54, 0x54, 0x54,
     0xBC, 0xE9, 0xEB, 0xEB, 0x93, 0x5F, 0x5C, 0x5C, 0x30, 0x8A, 0x9D, 0x2E, 0x2B, 0x2B, 0xBB, 0xA2,
     0x3E, 0x41, 0xBD, 0x21, 0x1E, 0x8F, 0x63, 0x6A, 0x6A, 0x0A, 0x81, 0x40, 0x00, 0x94, 0x1B, 0x3D,
     0x3D, 0x3D, 0x42, 0x3C, 0x96, 0x96, 0x96, 0x70, 0x7E, 0x7E, 0x8E, 0xE3, 0xE3, 0x63, 0xF8, 0xFD,
     0xFE, 0xB4, 0xD7, 0xEB, 0xF5, 0x8F, 0x8F, 0x8F, 0x5B, 0x68, 0x5E, 0x6F, 0x05, 0xCE, 0xB4, 0xE3,
     0xE8, 0xE8, 0x08, 0x27, 0x27, 0x27, 0xD8, 0xDF, 0xDF, 0xC7, 0xD9, 0xD9, 0x19, 0x6C, 0x36, 0x1B,
     0x36, 0x36, 0x36, 0x38, 0x9F, 0x85, 0x85, 0x05, 0xAC, 0xAF, 0xAF, 0x23, 0x1A, 0x8D, 0x22, 0x91,
     0x48, 0x20, 0x16, 0x8B, 0xFD, 0xDA, 0xDA, 0xDA, 0x7A, 0x41, 0x33, 0x7E, 0x57, 0x50, 0x50, 0x80,
     0x89, 0x89, 0x09, 0x84, 0xC3, 0x61, 0x6C, 0x6F, 0x6F, 0x23, 0x12, 0x89, 0xE0, 0xE0, 0xE0, 0x00,
     0x43, 0x43, 0x43, 0x58, 0x5E, 0x5E, 0xE6, 0x9C, 0x7D, 0x3E, 0x1F, 0x46, 0x47, 0x47, 0x79, 0xBE,
     0xBD, 0xBD, 0x3D, 0xE1, 0x3C, 0x1D, 0x0C, 0x06, 0x9F, 0x10, 0xB7, 0xC7, 0x84, 0x4F, 0xF6, 0xF7,
     0xF7, 0x63, 0x60, 0x60, 0x00, 0x83, 0x83, 0x83, 0x18, 0x19, 0x19, 0xC1, 0xDC, 0xDC, 0x1C, 0x8F,
     0x17, 0x7C, 0xA4, 0x27, 0xE7, 0x34, 0x39, 0x39, 0x89, 0x9D, 0x9D, 0x1D, 0x6E, 0x54, 0xE3, 0x13,
     0xE5, 0x34, 0x11, 0x37, 0x49, 0x51, 0x51, 0xD1, 0x4B, 0xA5, 0x52, 0xF9, 0x45, 0x26, 0x93, 0x5D,
     0x0A, 0xF3, 0x92, 0x48, 0x24, 0xA0, 0x6F, 0x14, 0x17, 0x17, 0xA3, 0xB6, 0xB6, 0x16, 0x5D, 0x5D,
     0x5D, 0x7C, 0x1E, 0xBB, 0xBB, 0xBB, 0x9C, 0xD7, 0xE1, 0xE1, 0x21, 0x42, 0xA1, 0xD0, 0x6B, 0xD2,
     0x45, 0x4C, 0x33, 0x12, 0x34, 0xCC, 0xA0, 0x19, 0x54, 0x92, 0x56, 0x0E, 0xD2, 0xD9, 0x43, 0xF8,
     0xCF, 0x82, 0x56, 0xC2, 0xDC, 0xEB, 0xEA, 0xEA, 0x38, 0x7E, 0x6C, 0x6C, 0x4C, 0xE0, 0xFE, 0x9D,
     0xB8, 0xBF, 0xA7, 0xFA, 0xAF, 0x56, 0x56, 0x56, 0xEE, 0x6D, 0x6E, 0x6E, 0xDE, 0xB8, 0x47, 0x55,
     0x55, 0x55, 0x6C, 0x66, 0x66, 0x46, 0x44, 0xDA, 0x3B, 0x34, 0x1A, 0x4D, 0x94, 0xB0, 0x3F, 0x09,
     0x7B, 0x45, 0xBD, 0xA5, 0x5D, 0x2E, 0x57, 0x8C, 0x7A, 0x73, 0xD9, 0xED, 0xF6, 0x3B, 0x84, 0xFF,
     0xE7, 0x7D, 0xA6, 0x3A, 0x2C, 0x95, 0x4A, 0xB1, 0x8E, 0x8E, 0x0E, 0x6D, 0x77, 0x77, 0xB7, 0xCD,
     0xE9, 0x74, 0x3E, 0x73, 0xBB, 0xDD, 0x8F, 0x3C, 0x1E, 0x8F, 0xE6, 0xF4, 0xF4, 0x94, 0xAD, 0xAD,
     0xAD, 0xDD, 0xDE, 0xCF, 0x73, 0x0B, 0x0B, 0xB8, 0xB6, 0xE0, 0x5D, 0xC6, 0x66, 0xC5, 0xE4, 0x10,
     0x4C, 0xF4, 0xF7, 0xD8, 0x59, 0xF2, 0x7F, 0xA3, 0xB8, 0xB4, 0xFC, 0x0F, 0xEE, 0x37, 0x70, 0xEC,
     0x16, 0x4A, 0x7E, 0x04, 0x00, 0x00};
    AsyncWebServerResponse *response = request->beginResponse_P(200, "image/x-icon", favicon_ico_gz, favicon_ico_gz_len);
    response->addHeader("Content-Encoding", "gzip");
    request->send(response);

    响应来自流的内容

    //read 12 bytes from Serial and send them as Content Type text/plainrequest->send(Serial, "text/plain", 12);

    响应来自流和额外标题的内容

    //read 12 bytes from Serial and send them as Content Type text/plainAsyncWebServerResponse *response = request->beginResponse(Serial, "text/plain", 12);
    response->addHeader("Server","ESP Async Web Server");
    request->send(response);

    响应来自包含模板的流的内容

    String processor(const String& var)
    {
     if(var == "HELLO_FROM_TEMPLATE")
     returnF("Hello world!");
     returnString();
    }//.. .//read 12 bytes from Serial and send them as Content Type text/plainrequest->send(Serial, "text/plain", 12, processor);

    响应来自包含模板和附加标题的流的内容

    String processor(const String& var)
    {
     if(var == "HELLO_FROM_TEMPLATE")
     returnF("Hello world!");
     returnString();
    }//.. .//read 12 bytes from Serial and send them as Content Type text/plainAsyncWebServerResponse *response = request->beginResponse(Serial, "text/plain", 12, processor);
    response->addHeader("Server","ESP Async Web Server");
    request->send(response);

    响应来自文件的内容

    //Send index.htm with default content typerequest->send(SPIFFS, "/index.htm");//Send index.htm as textrequest->send(SPIFFS, "/index.htm", "text/plain");//Download index.htmrequest->send(SPIFFS, "/index.htm", String(), true);

    响应来自文件和额外标题的内容

    //Send index.htm with default content typeAsyncWebServerResponse *response = request->beginResponse(SPIFFS, "/index.htm");//Send index.htm as textAsyncWebServerResponse *response = request->beginResponse(SPIFFS, "/index.htm", "text/plain");//Download index.htmAsyncWebServerResponse *response = request->beginResponse(SPIFFS, "/index.htm", String(), true);
    response->addHeader("Server","ESP Async Web Server");
    request->send(response);

    响应来自包含模板的文件的内容

    内部使用块响应函数。

    Index.htm 内容:

    %HELLO_FROM_TEMPLATE%

    源文件中的某个位置:

    String processor(const String& var)
    {
     if(var == "HELLO_FROM_TEMPLATE")
     returnF("Hello world!");
     returnString();
    }//.. .//Send index.htm with template processor functionrequest->send(SPIFFS, "/index.htm", String(), false, processor);

    使用回调响应内容

    //send 128 bytes as plain textrequest->send("text/plain", 128, [](uint8_t *buffer, size_t maxLen, size_t index) -> size_t {
     //Write up to"maxLen" bytes into"buffer" and return the amount written.//index equals the amount of bytes that have been already sent//You will not be asked for more bytes once the content length has been reached.//Keep in mind that you can not delay or yield waiting for more data!//Send what you currently have and you will be asked for more againreturn mySource.read(buffer, maxLen);
    });

    使用回调和附加标题响应内容

    //send 128 bytes as plain textAsyncWebServerResponse *response = request->beginResponse("text/plain", 128, [](uint8_t *buffer, size_t maxLen, size_t index) -> size_t {
     //Write up to"maxLen" bytes into"buffer" and return the amount written.//index equals the amount of bytes that have been already sent//You will not be asked for more bytes once the content length has been reached.//Keep in mind that you can not delay or yield waiting for more data!//Send what you currently have and you will be asked for more againreturn mySource.read(buffer, maxLen);
    });
    response->addHeader("Server","ESP Async Web Server");
    request->send(response);

    使用包含模板的回调来响应内容

    String processor(const String& var)
    {
     if(var == "HELLO_FROM_TEMPLATE")
     returnF("Hello world!");
     returnString();
    }//.. .//send 128 bytes as plain textrequest->send("text/plain", 128, [](uint8_t *buffer, size_t maxLen, size_t index) -> size_t {
     //Write up to"maxLen" bytes into"buffer" and return the amount written.//index equals the amount of bytes that have been already sent//You will not be asked for more bytes once the content length has been reached.//Keep in mind that you can not delay or yield waiting for more data!//Send what you currently have and you will be asked for more againreturn mySource.read(buffer, maxLen);
    }, processor);

    使用包含模板和额外标题的回调来响应

    String processor(const String& var)
    {
     if(var == "HELLO_FROM_TEMPLATE")
     returnF("Hello world!");
     returnString();
    }//.. .//send 128 bytes as plain textAsyncWebServerResponse *response = request->beginResponse("text/plain", 128, [](uint8_t *buffer, size_t maxLen, size_t index) -> size_t {
     //Write up to"maxLen" bytes into"buffer" and return the amount written.//index equals the amount of bytes that have been already sent//You will not be asked for more bytes once the content length has been reached.//Keep in mind that you can not delay or yield waiting for more data!//Send what you currently have and you will be asked for more againreturn mySource.read(buffer, maxLen);
    }, processor);
    response->addHeader("Server","ESP Async Web Server");
    request->send(response);

    块响应

    当内容长度未知时使用。 如果客户端支持 http/1.1,则效果最佳

    AsyncWebServerResponse *response = request->beginChunkedResponse("text/plain", [](uint8_t *buffer, size_t maxLen, size_t index) -> size_t {
     //Write up to"maxLen" bytes into"buffer" and return the amount written.//index equals the amount of bytes that have been already sent//You will be asked for more data until 0 is returned//Keep in mind that you can not delay or yield waiting for more data!return mySource.read(buffer, maxLen);
    });
    response->addHeader("Server","ESP Async Web Server");
    request->send(response);

    包含模板的块响应

    当内容长度未知时使用。 如果客户端支持 http/1.1,则效果最佳

    String processor(const String& var)
    {
     if(var == "HELLO_FROM_TEMPLATE")
     returnF("Hello world!");
     returnString();
    }//.. .AsyncWebServerResponse *response = request->beginChunkedResponse("text/plain", [](uint8_t *buffer, size_t maxLen, size_t index) -> size_t {
     //Write up to"maxLen" bytes into"buffer" and return the amount written.//index equals the amount of bytes that have been already sent//You will be asked for more data until 0 is returned//Keep in mind that you can not delay or yield waiting for more data!return mySource.read(buffer, maxLen);
    }, processor);
    response->addHeader("Server","ESP Async Web Server");
    request->send(response);

    打印到响应

    AsyncResponseStream *response = request->beginResponseStream("text/html");
    response->addHeader("Server","ESP Async Web Server");
    response->printf("<!DOCTYPE html><html><head><title>Webpage at %s</title></head><body>", request->url().c_str());
    response->print("<h2>Hello ");
    response->print(request->client()->remoteIP());
    response->print("</h2>");
    response->print("<h3>General</h3>");
    response->print("<ul>");
    response->printf("<li>Version: HTTP/1.%u</li>", request->version());
    response->printf("<li>Method: %s</li>", request->methodToString());
    response->printf("<li>URL: %s</li>", request->url().c_str());
    response->printf("<li>Host: %s</li>", request->host().c_str());
    response->printf("<li>ContentType: %s</li>", request->contentType().c_str());
    response->printf("<li>ContentLength: %u</li>", request->contentLength());
    response->printf("<li>Multipart: %s</li>", request->multipart()?"true":"false");
    response->print("</ul>");
    response->print("<h3>Headers</h3>");
    response->print("<ul>");int headers = request->headers();for(int i=0;i<headers;i++){
     AsyncWebHeader* h = request->getHeader(i);
     response->printf("<li>%s: %s</li>", h->name().c_str(), h->value().c_str());
    }
    response->print("</ul>");
    response->print("<h3>Parameters</h3>");
    response->print("<ul>");int params = request->params();for(int i=0;i<params;i++){
     AsyncWebParameter* p = request->getParam(i);
     if(p->isFile()){
     response->printf("<li>FILE[%s]: %s, size: %u</li>", p->name().c_str(), p->value().c_str(), p->size());
     } elseif(p->isPost()){
     response->printf("<li>POST[%s]: %s</li>", p->name().c_str(), p->value().c_str());
     } else {
     response->printf("<li>GET[%s]: %s</li>", p->name().c_str(), p->value().c_str());
     }
    }
    response->print("</ul>");
    response->print("</body></html>");//send the response lastrequest->send(response);

    ArduinoJson基本响应

    这种发送Json的方式在结果低于 4 KB时非常有用

    #include"AsyncJson.h"#include"ArduinoJson.h"AsyncResponseStream *response = request->beginResponseStream("text/json");
    DynamicJsonBuffer jsonBuffer;
    JsonObject &root = jsonBuffer.createObject();
    root["heap"] = ESP.getFreeHeap();
    root["ssid"] = WiFi.SSID();
    root.printTo(*response);
    request->send(response);

    ArduinoJson高级响应

    这个响应可以处理非常大的Json对象:如果在每次需要发送数据时都没有明显的速度降低,因为不允许读取字符串,这显示了速度降低了,从而显示了速度降低的Json数据包

    #include"AsyncJson.h"#include"ArduinoJson.h"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);

    服务 static-文件

    除了从SPIFFS提供文件,服务器提供一个专门的处理程序,以优化服务的性能,从 SPIFFS - AsyncStaticWebHandler - 。 使用 server.serveStatic() 函数将 AsyncStaticWebHandler的新实例初始化并添加到服务器。 如果文件不存在,处理程序将不处理请求,比如 将继续查找它的他处理请求的处理程序。 注意,你可以以链接setter函数来设置处理程序,或者者保留一个指针来更改它的时间。

    按名称服务特定文件

    // Serve the file"/www/page.htm" when request url is"/page.htm"server.serveStatic("/page.htm", SPIFFS, "/www/page.htm");

    服务目录中的文件

    若要在目录中提供文件,文件的路径应在SPIFFS中指定一个目录,并以"/"结束。

    // Serve files in directory"/www/" when request url starts with"/"// Request to the root or none existing files will try to server the defualt// file name"index.htm" if existsserver.serveStatic("/", SPIFFS, "/www/");// Server with different default fileserver.serveStatic("/", SPIFFS, "/www/").setDefaultFile("default.html");

    使用认证服务 static-文件

    server
    . serveStatic("/", SPIFFS, "/www/")
    . setDefaultFile("default.html")
    . setAuthentication("user", "pass");

    指定高速缓存控制头

    在客户端加载文件后,可以指定缓存控制头值以减少对服务器的调用次数。 有关缓存控制值的更多信息,请参见缓存控件

    // Cache responses for 10 minutes (600 seconds)server.serveStatic("/", SPIFFS, "/www/").setCacheControl("max-age=600");//*** Change Cache-Control after server setup ***// During setup - keep a pointer to the handlerAsyncStaticWebHandler* handler = &server.serveStatic("/", SPIFFS, "/www/").setCacheControl("max-age=600");// At a later event - change Cache-Controlhandler->setCacheControl("max-age=30");

    指定日期修改头

    可以以指定日期修改头,使服务器能够返回具有相同值的"if-modified-since"头的请求不修改的( 304 ) 响应。

    // Update the date modified string every time files are updatedserver.serveStatic("/", SPIFFS, "/www/").setLastModified("Mon, 20 Jun 2016 14:00:00 GMT");//*** Chage last modified value at a later stage ***// During setup - read last modified value from config or EEPROMString date_modified = loadDateModified();
    AsyncStaticWebHandler* handler = &server.serveStatic("/", SPIFFS, "/www/");
    handler->setLastModified(date_modified);// At a later event when files are updatedString date_modified = getNewDateModfied();saveDateModified(date_modified); // Save for next resethandler->setLastModified(date_modified);

    指定模板处理器回调

    为 static 文件指定模板处理器是可能的。 有关模板处理器的信息,请参见响应内容来自文件包含模板模板。

    String processor(const String& var)
    {
     if(var == "HELLO_FROM_TEMPLATE")
     returnF("Hello world!");
     returnString();
    }//.. .server.serveStatic("/", SPIFFS, "/www/").setTemplateProcessor(processor);

    使用过滤器

    筛选器可以设置为 Rewrite 或者 Handler,以便控制什么时候应用重写并考虑处理程序。 过滤器是一个回调函数,用于计算请求并返回布尔 true 以包含要排除该请求的项或者 false 。 提供了两个过滤器回调,用于说服:

    • ON_STA_FILTER - 对 STA ( 站模式) 接口进行请求时的return true 。
    • ON_AP_FILTER - 对 AP ( 访问点) 接口进行请求时的return true 。

    在AP模式下提供不同的站点文件

    server.serveStatic("/", SPIFFS, "/www/").setFilter(ON_STA_FILTER);
    server.serveStatic("/", SPIFFS, "/ap/").setFilter(ON_AP_FILTER);

    对AP上的不同索引进行重写

    // Serve the file"/www/index-ap.htm" in AP, and the file"/www/index.htm" on STAserver.rewrite("/", "index.htm");
    server.rewrite("/index.htm", "index-ap.htm").setFilter(ON_AP_FILTER);
    server.serveStatic("/", SPIFFS, "/www/");

    服务不同主机

    // Filter callback using request hostboolfilterOnHost1(AsyncWebServerRequest *request) { return request->host() == "host1"; }// Server setup: server files in"/host1/" to requests for"host1", and files in"/www/" otherwise.server.serveStatic("/", SPIFFS, "/host1/").setFilter(filterOnHost1);
    server.serveStatic("/", SPIFFS, "/www/");

    错误响应

    某些响应已经实现,但你不应使用它们,因为它们不符合 HTTP 。 下面的示例将导致连接的不完整关闭,而不是提供内容长度的更多时间。

    使用不带内容长度的回调对内容进行 /1的响应

    //This is used as fallback for chunked responses to HTTP/1.0 Clientsrequest->send("text/plain", 0, [](uint8_t *buffer, size_t maxLen, size_t index) -> size_t {
     //Write up to"maxLen" bytes into"buffer" and return the amount written.//You will be asked for more data until 0 is returned//Keep in mind that you can not delay or yield waiting for more data!return mySource.read(buffer, maxLen);
    });

    异步 web socket插件

    服务器包含一个网络套接字插件,它允许你定义不同的web socket位置来连接到不启动其他侦听服务或者使用不同端口

    异步 web socket事件

    voidonEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventType type, void * arg, uint8_t *data, size_t len){
     if(type == WS_EVT_CONNECT){
     //client connectedos_printf("ws[%s][%u] connectn", server->url(), client->id());
     client->printf("Hello Client %u :)", client->id());
     client->ping();
     } elseif(type == WS_EVT_DISCONNECT){
     //client disconnectedos_printf("ws[%s][%u] disconnect: %un", server->url(), client->id());
     } elseif(type == WS_EVT_ERROR){
     //error was received from the other endos_printf("ws[%s][%u] error(%u): %sn", server->url(), client->id(), *((uint16_t*)arg), (char*)data);
     } elseif(type == WS_EVT_PONG){
     //pong message was received (in response to a ping request maybe)os_printf("ws[%s][%u] pong[%u]: %sn", server->url(), client->id(), len, (len)?(char*)data:"");
     } elseif(type == WS_EVT_DATA){
     //data packet AwsFrameInfo * info = (AwsFrameInfo*)arg;
     if(info->final && info->index == 0 && info->len == len){
     //the whole message is in a single frame and we got all of it's dataos_printf("ws[%s][%u] %s-message[%llu]: ", server->url(), client->id(), (info->opcode == WS_TEXT)?"text":"binary", info->len);
     if(info->opcode == WS_TEXT){
     data[len] = 0;
     os_printf("%sn", (char*)data);
     } else {
     for(size_t i=0; i <info->len; i++){
     os_printf("%02x ", data[i]);
     }
     os_printf("n");
     }
     if(info->opcode == WS_TEXT)
     client->text("I got your text message");
     else client->binary("I got your binary message");
     } else {
     //message is comprised of multiple frames or the frame is split into multiple packetsif(info->index == 0){
     if(info->num == 0)
     os_printf("ws[%s][%u] %s-message startn", server->url(), client->id(), (info->message_opcode == WS_TEXT)?"text":"binary");
     os_printf("ws[%s][%u] frame[%u] start[%llu]n", server->url(), client->id(), info->num, info->len);
     }
     os_printf("ws[%s][%u] frame[%u] %s[%llu - %llu]: ", server->url(), client->id(), info->num, (info->message_opcode == WS_TEXT)?"text":"binary", info->index, info->index + len);
     if(info->message_opcode == WS_TEXT){
     data[len] = 0;
     os_printf("%sn", (char*)data);
     } else {
     for(size_t i=0; i <len; i++){
     os_printf("%02x ", data[i]);
     }
     os_printf("n");
     }
     if((info->index + len) == info->len){
     os_printf("ws[%s][%u] frame[%u] end[%llu]n", server->url(), client->id(), info->num, info->len);
     if(info->final){
     os_printf("ws[%s][%u] %s-message endn", server->url(), client->id(), (info->message_opcode == WS_TEXT)?"text":"binary");
     if(info->message_opcode == WS_TEXT)
     client->text("I got your text message");
     else client->binary("I got your binary message");
     }
     }
     }
     }
    }

    将数据发送到套接字客户端的方法

    //Server methodsAsyncWebSocket ws("/ws");//printf to a clientws.printf((uint32_t)client_id, arguments...);//printf to all clientsws.printfAll(arguments...);//printf_P to a clientws.printf_P((uint32_t)client_id, PSTR(format), arguments...);//printfAll_P to all clientsws.printfAll_P(PSTR(format), arguments...);//send text to a clientws.text((uint32_t)client_id, (char*)text);
    ws.text((uint32_t)client_id, (uint8_t*)text, (size_t)len);//send text from PROGMEM to a clientws.text((uint32_t)client_id, PSTR("text"));constchar flash_text[] PROGMEM = "Text to send"ws.text((uint32_t)client_id, FPSTR(flash_text));//send text to all clientsws.textAll((char*)text);
    ws.textAll((uint8_t*)text, (size_t)len);//send binary to a clientws.binary((uint32_t)client_id, (char*)binary);
    ws.binary((uint32_t)client_id, (uint8_t*)binary, (size_t)len);//send binary from PROGMEM to a clientconstuint8_t flash_binary[] PROGMEM = { 0x01, 0x02, 0x03, 0x04 };
    ws.binary((uint32_t)client_id, flash_binary, 4);//send binary to all clientsws.binaryAll((char*)binary);
    ws.binaryAll((uint8_t*)binary, (size_t)len);//HTTP Authenticate before switch to Websocket protocolws.setAuthentication("user", "pass");//client methodsAsyncWebSocketClient * client;//printfclient->printf(arguments...);//printf_Pclient->printf_P(PSTR(format), arguments...);//send textclient->text((char*)text);
    client->text((uint8_t*)text, (size_t)len);//send text from PROGMEMclient->text(PSTR("text"));constchar flash_text[] PROGMEM = "Text to send";
    client->text(FPSTR(flash_text));//send binaryclient->binary((char*)binary);
    client->binary((uint8_t*)binary, (size_t)len);//send binary from PROGMEMconstuint8_t flash_binary[] PROGMEM = { 0x01, 0x02, 0x03, 0x04 };
    client->binary(flash_binary, 4);

    直接访问网络套接字消息缓冲区

    当使用上述方法发送网络套接字消息时,会创建一个。 在某些情况下,你可能希望直接操作或者填充该缓冲区,例如防止数据的不必要重复。 下面的示例演示如何创建缓冲区并从ArduinoJson对象打印数据,然后将它的发送到。

    voidsendDataWs(AsyncWebSocketClient * client)
    {
     DynamicJsonBuffer jsonBuffer;
     JsonObject& root = jsonBuffer.createObject();
     root["a"] = "abc";
     root["b"] = "abcd";
     root["c"] = "abcde";
     root["d"] = "abcdef";
     root["e"] = "abcdefg";
     size_t len = root.measureLength();
     AsyncWebSocketMessageBuffer * buffer = ws.makeBuffer(len); // creates a buffer (len + 1) for you.if (buffer) {
     root.printTo((char *)buffer->get(), len + 1);
     if (client) {
     client->text(buffer);
     } else {
     ws.textAll(buffer);
     }
     }
    }

    异步事件源插件

    服务器包含 EventSource ( 服务器发送的事件) 插件,可以用于向浏览器发送短文本事件。 EventSource与WebSockets的区别在于,EventSource是单方向的,文本只。

    服务器上的安装事件源

    AsyncWebServer server(80);
    AsyncEventSource events("/events");voidsetup(){
     // setup.. .... events.onConnect([](AsyncEventSourceClient *client){
     if(client->lastId()){
     Serial.printf("Client reconnected! Last message ID that it gat is: %un", client->lastId());
     }
     //send event with message"hello!", id current millis// and set reconnect delay to 1 second client->send("hello!",NULL,millis(),1000);
     });
     //HTTP Basic authentication events.setAuthentication("user", "pass");
     server.addHandler(&events);
     // setup.. ....}voidloop(){
     if(eventTriggered){ // your logic here//send event"myevent" events.send("my event content","myevent",millis());
     }
    }

    在浏览器中设置事件源

    if (!!window.EventSource) {
     var source =newEventSource('/events');
     source.addEventListener('open', function(e) {
     console.log("Events Connected");
     }, false);
     source.addEventListener('error', function(e) {
     if (e.target.readyState!=EventSource.OPEN) {
     console.log("Events Disconnected");
     }
     }, false);
     source.addEventListener('message', function(e) {
     console.log("message", e.data);
     }, false);
     source.addEventListener('myevent', function(e) {
     console.log("myevent", e.data);
     }, false);
    }

    正在扫描可用的WiFi网络

    //First request will return 0 results unless you start scan from somewhere else (loop/setup)//Do not request more often than 3-5 secondsserver.on("/scan", HTTP_GET, [](AsyncWebServerRequest *request){
     String json = "[";
     int n = WiFi.scanComplete();
     if(n == -2){
     WiFi.scanNetworks(true);
     } elseif(n){
     for (int i = 0; i <n; ++i){
     if(i) json += ",";
     json += "{";
     json += ""rssi":"+String(WiFi.RSSI(i));
     json += ","ssid":""+WiFi.SSID(i)+""";
     json += ","bssid":""+WiFi.BSSIDstr(i)+""";
     json += ","channel":"+String(WiFi.channel(i));
     json += ","secure":"+String(WiFi.encryptionType(i));
     json += ","hidden":"+String(WiFi.isHidden(i)?"true":"false");
     json += "}";
     }
     WiFi.scanDelete();
     if(WiFi.scanComplete() == -2){
     WiFi.scanNetworks(true);
     }
     }
     json += "]";
     request->send(200, "text/json", json);
     json = String();
    });

    删除处理程序并重写

    服务器按照与添加处理程序相同的顺序进行处理。 不能简单地添加具有相同路径的处理程序来替代它们。 要删除处理程序:

    //save callback for particular URL path
    auto handler = server.on("/some/path", [](AsyncWebServerRequest *request){
    //do something useful
    });
    //when you don't need handler anymore remove it
    server.removeHandler(&handler);
    //same with rewrites
    server.removeRewrite(&someRewrite);
    server.onNotFound([](AsyncWebServerRequest *request){
     request->send(404);
    });
    //remove server.onNotFound handler
    server.onNotFound(NULL);
    //remove all rewrites, handlers and onNotFound/onFileUpload/onRequestBody callbacks
    server.reset();

    设置服务器

    #include"ESPAsyncTCP.h"#include"ESPAsyncWebServer.h"AsyncWebServer server(80);
    AsyncWebSocket ws("/ws"); // access at ws://[esp ip]/wsAsyncEventSource events("/events"); // event source (Server-Sent events)constchar* ssid = "your-ssid";constchar* password = "your-pass";constchar* http_username = "admin";constchar* http_password = "admin";//flag to use from web update to reboot the ESPbool shouldReboot = false;voidonRequest(AsyncWebServerRequest *request){
     //Handle Unknown Request request->send(404);
    }voidonBody(AsyncWebServerRequest *request, uint8_t *data, size_t len, size_t index, size_t total){
     //Handle body}voidonUpload(AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final){
     //Handle upload}voidonEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventType type, void * arg, uint8_t *data, size_t len){
     //Handle WebSocket event}voidsetup(){
     Serial.begin(115200);
     WiFi.mode(WIFI_STA);
     WiFi.begin(ssid, password);
     if (WiFi.waitForConnectResult()!= WL_CONNECTED) {
     Serial.printf("WiFi Failed!n");
     return;
     }
     // attach AsyncWebSocket ws.onEvent(onEvent);
     server.addHandler(&ws);
     // attach AsyncEventSource server.addHandler(&events);
     // respond to GET requests on URL/heap server.on("/heap", HTTP_GET, [](AsyncWebServerRequest *request){
     request->send(200, "text/plain", String(ESP.getFreeHeap()));
     });
     // upload a file to/upload server.on("/upload", HTTP_POST, [](AsyncWebServerRequest *request){
     request->send(200);
     }, onUpload);
     // send a file when/index is requested server.on("/index", HTTP_ANY, [](AsyncWebServerRequest *request){
     request->send(SPIFFS, "/index.htm");
     });
     // HTTP basic authentication server.on("/login", HTTP_GET, [](AsyncWebServerRequest *request){
     if(!request->authenticate(http_username, http_password))
     return request->requestAuthentication();
     request->send(200, "text/plain", "Login Success!");
     });
     // Simple Firmware Update Form server.on("/update", HTTP_GET, [](AsyncWebServerRequest *request){
     request->send(200, "text/html", "<form method='POST' action='/update' enctype='multipart/form-data'><input type='file' name='update'><input type='submit' value='Update'></form>");
     });
     server.on("/update", HTTP_POST, [](AsyncWebServerRequest *request){
     shouldReboot =!Update.hasError();
     AsyncWebServerResponse *response = request->beginResponse(200, "text/plain", shouldReboot?"OK":"FAIL");
     response->addHeader("Connection", "close");
     request->send(response);
     },[](AsyncWebServerRequest *request, String filename, size_tindex, uint8_t *data, size_t len, bool final){
     if(!index){
     Serial.printf("Update Start: %sn", filename.c_str());
     Update.runAsync(true);
     if(!Update.begin((ESP.getFreeSketchSpace() - 0x1000) & 0xFFFFF000)){
     Update.printError(Serial);
     }
     }
     if(!Update.hasError()){
     if(Update.write(data, len)!= len){
     Update.printError(Serial);
     }
     }
     if(final){
     if(Update.end(true)){
     Serial.printf("Update Success: %uBn", index+len);
     } else {
     Update.printError(Serial);
     }
     }
     });
     // attach filesystem root at URL/fs server.serveStatic("/fs", SPIFFS, "/");
     // Catch-All Handlers// Any request that can not find a Handler that canHandle it// ends in the callbacks below. server.onNotFound(onRequest);
     server.onFileUpload(onUpload);
     server.onRequestBody(onBody);
     server.begin();
    }voidloop(){
     if(shouldReboot){
     Serial.println("Rebooting...");
     delay(100);
     ESP.restart();
     }
     staticchar temp[128];
     sprintf(temp, "Seconds since boot: %u", millis()/1000);
     events.send(temp, "time"); //send event"time"}

    将全局和类函数作为请求处理程序

    #include <Arduino.h>
    #include <ESPAsyncWebserver.h>
    #include <Hash.h>
    #include <functional>
    void handleRequest(AsyncWebServerRequest *request)
    {
    }
    class WebClass
    {
    public :
     WebClass(){
     };
     AsyncWebServer classWebServer = AsyncWebServer(80);
     void classRequest (AsyncWebServerRequest *request)
     {
     }
     void begin(){
    //attach global request handler
     classWebServer.on("/example", HTTP_ANY, handleRequest);
    //attach class request handler
     classWebServer.on("/example", HTTP_ANY, std::bind(&WebClass::classRequest, this, std::placeholders::_1));
     }
    };
    AsyncWebServer globalWebServer(80);
    WebClass webClassInstance;
    void setup() {
    //attach global request handler
     globalWebServer.on("/example", HTTP_ANY, handleRequest);
    //attach class request handler
     globalWebServer.on("/example", HTTP_ANY, std::bind(&WebClass::classRequest, webClassInstance, std::placeholders::_1));
    }
    void loop() {
    }

    控制 web socket连接的方法

    //Disable client connections if it was activated
     if ( ws.enabled() )
     ws.enable(false);
    //enable client connections if it was disabled
     if (!ws.enabled() )
     ws.enable(true);

    OTA代码示例

    //OTA callbacks
     ArduinoOTA.onStart([]() {
    //Clean SPIFFS
     SPIFFS.end();
    //Disable client connections 
     ws.enable(false);
    //Advertise connected clients what's going on
     ws.textAll("OTA Update Started");
    //Close them
     ws.closeAll();
     });

    添加默认标题

    有时在使用CORS时,或者使用某种自定义身份验证系统,你可能需要定义一个头,该头应该添加到所有响应系统。 DefaultHeaders单例允许你执行这里操作。

    例如:

    DefaultHeaders::Instance().addHeader("Access-Control-Allow-Origin","*");
    webServer.begin();

    注意:大多数情况下,你仍然需要对CORS预飞行的选择方法作出响应。 ( 除非你仅使用 GET )

    这是一个选项:

    webServer.onNotFound([](AsyncWebServerRequest *request) {
     if (request->method() == HTTP_OPTIONS) {
     request->send(200);
     } else {
     request->send(404);
     }
    });



    Copyright © 2011 HelpLib All rights reserved.    知识分享协议 京ICP备05059198号-3  |  如果智培  |  酷兔英语