### Example Application Main Function Source: https://github.com/esp32async/espasyncwebserver/blob/main/docs/hosted-build.md This C++ code demonstrates the main entry point for the hosted ESPAsyncWebServer application. It sets up a basic HTTP server with a root handler and a not found handler, then initializes the PosixAsyncTCP manager and starts the server. ```cpp #include #include #include static AsyncWebServer server(8080); void setup() { server.on("/", HTTP_GET, [](AsyncWebServerRequest *request) { request->send(200, "text/plain", "ESPAsyncWebServer host app is running on port 8080\n"); }); server.onNotFound([](AsyncWebServerRequest *request) { request->send(404, "text/plain", "Not found\n"); }); PosixAsyncTCPManager::getInstance().begin(); server.begin(); } void loop() { delay(1000); } ``` -------------------------------- ### ESPAsyncWebServer Setup and Configuration Source: https://github.com/esp32async/espasyncwebserver/wiki/Home This code demonstrates the complete setup of an ESPAsyncWebServer, including WiFi connection, handling WebSockets and Server-Sent Events, routing various HTTP requests, implementing basic authentication, and managing firmware updates. It also shows how to serve static files and set up catch-all handlers. ```cpp #include "ESPAsyncTCP.h" #include "ESPAsyncWebServer.h" AsyncWebServer server(80); AsyncWebSocket ws("/ws"); // access at ws://[esp ip]/ws AsyncEventSource events("/events"); // event source (Server-Sent events) const char* ssid = "your-ssid"; const char* password = "your-pass"; const char* http_username = "admin"; const char* http_password = "admin"; //flag to use from web update to reboot the ESP bool shouldReboot = false; void onRequest(AsyncWebServerRequest *request){ //Handle Unknown Request request->send(404); } void onBody(AsyncWebServerRequest *request, uint8_t *data, size_t len, size_t index, size_t total){ //Handle body } void onUpload(AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final){ //Handle upload } void onEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventType type, void * arg, uint8_t *data, size_t len){ //Handle WebSocket event } void setup(){ 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", "
"); }); 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_t index, uint8_t *data, size_t len, bool final){ if(!index){ Serial.printf("Update Start: %s\n", 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: %uB\n", 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(); } void loop(){ if(shouldReboot){ Serial.println("Rebooting..."); delay(100); ESP.restart(); } static char temp[128]; sprintf(temp, "Seconds since boot: %u", millis()/1000); events.send(temp, "time"); //send event "time" } ``` -------------------------------- ### ESPAsyncWebServer Setup and Handlers Source: https://github.com/esp32async/espasyncwebserver/blob/main/docs/setup.md This code demonstrates the basic setup of an AsyncWebServer, including WiFi connection, attaching WebSockets and EventSources, and defining handlers for various routes like '/heap', '/upload', '/index', and '/update'. It also shows how to serve static files from SPIFFS or LittleFS and includes catch-all handlers for not found, file uploads, and request bodies. ```cpp #include #if defined(ESP32) || defined(LIBRETINY) #include #include #elif defined(ESP8266) #include #include #elif defined(TARGET_RP2040) || defined(TARGET_RP2350) || defined(PICO_RP2040) || defined(PICO_RP2350) #include #include #endif #include AsyncWebServer server(80); AsyncWebSocket ws("/ws"); // access at ws://[esp ip]/ws AsyncEventSource events("/events"); // event source (Server-Sent events) const char* ssid = "your-ssid"; const char* password = "your-pass"; //flag to use from web update to reboot the ESP bool shouldReboot = false; void onRequest(AsyncWebServerRequest *request){ //Handle Unknown Request request->send(404); } void onBody(AsyncWebServerRequest *request, uint8_t *data, size_t len, size_t index, size_t total){ //Handle body } void onUpload(AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final){ //Handle upload } void onEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventType type, void * arg, uint8_t *data, size_t len){ //Handle WebSocket event } void setup(){ 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 (SPIFFS example) server.on("/index", HTTP_ALL, [](AsyncWebServerRequest *request){ request->send(SPIFFS, "/index.htm"); }); // send a file when /index is requested (LittleFS example) server.on("/index", HTTP_ALL, [](AsyncWebServerRequest *request){ request->send(LittleFS, "/index.htm"); }); // Simple Firmware Update Form server.on("/update", HTTP_GET, [](AsyncWebServerRequest *request){ request->send(200, "text/html", "
"); }); 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_t index, uint8_t *data, size_t len, bool final){ if(!index){ Serial.printf("Update Start: %s\n", 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: %uB\n", index+len); } else { Update.printError(Serial); } } }); // attach filesystem root at URL /fs (SPIFFS example) server.serveStatic("/fs", SPIFFS, "/"); // attach filesystem root at URL /fs (LittleFS example) server.serveStatic("/fs", LittleFS, "/"); // 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(); } void loop(){ if(shouldReboot){ Serial.println("Rebooting..."); delay(100); ESP.restart(); } static char temp[128]; sprintf(temp, "Seconds since boot: %u", millis()/1000); events.send(temp, "time"); //send event "time" } ``` -------------------------------- ### Factory Method URL Matching Examples Source: https://github.com/esp32async/espasyncwebserver/blob/main/examples/arduino/URIMatcher/README.md Examples using factory methods like `exact`, `prefix`, `dir`, and `ext` for precise URL routing. ```plaintext http://192.168.4.1/exact ``` ```plaintext http://192.168.4.1/service/status ``` ```plaintext http://192.168.4.1/admin/users ``` ```plaintext http://192.168.4.1/images/photo.jpg ``` -------------------------------- ### Install Autocannon for Performance Testing Source: https://github.com/esp32async/espasyncwebserver/wiki/Home Use Homebrew to install the autocannon tool for load testing the web server. ```bash > brew install autocannon > autocannon -c 10 -w 10 -d 20 http://192.168.4.1 ``` -------------------------------- ### File Serving - Images Source: https://github.com/esp32async/espasyncwebserver/blob/main/examples/arduino/URIMatcher/README.md Example of using `AsyncURIMatcher::ext` to serve image files. ```cpp server.on(AsyncURIMatcher::ext("/images/*.jpg"), serveImageFiles); ``` -------------------------------- ### Setup Server-Sent Events (EventSource) Source: https://github.com/esp32async/espasyncwebserver/wiki/Home Configure an AsyncEventSource handler on the server to send text events to the browser. Use `onConnect` for initial client setup and `setAuthentication` for basic auth. Events can be sent with custom IDs and reconnect delays. ```cpp AsyncWebServer server(80); AsyncEventSource events("/events"); void setup(){ // setup ...... events.onConnect([](AsyncEventSourceClient *client){ if(client->lastId()){ Serial.printf("Client reconnected! Last message ID that it gat is: %u\n", 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 ...... } void loop(){ if(eventTriggered){ // your logic here //send event "myevent" events.send("my event content","myevent",millis()); } } ``` -------------------------------- ### File Serving - CSS and JS Source: https://github.com/esp32async/espasyncwebserver/blob/main/examples/arduino/URIMatcher/README.md Example of using `AsyncURIMatcher::ext` to serve CSS and JavaScript files. ```cpp // Serve different file types server.on(AsyncURIMatcher::ext("/assets/*.css"), serveCSSFiles); server.on(AsyncURIMatcher::ext("/assets/*.js"), serveJSFiles); ``` -------------------------------- ### Regex URL Matching Examples Source: https://github.com/esp32async/espasyncwebserver/blob/main/examples/arduino/URIMatcher/README.md Examples of using regular expressions for advanced URL matching, requires `ASYNCWEBSERVER_REGEX` compilation flag. ```plaintext http://192.168.4.1/user/123 ``` ```plaintext http://192.168.4.1/user/456 ``` -------------------------------- ### Setup Global and Class Request Handlers Source: https://github.com/esp32async/espasyncwebserver/wiki/Home Demonstrates how to attach both global functions and class methods as request handlers to an AsyncWebServer instance. Ensure necessary headers are included. ```cpp #include #include #include #include void handleRequest(AsyncWebServerRequest *request){} class WebClass { public : AsyncWebServer classWebServer = AsyncWebServer(81); WebClass(){}; 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() { } ``` -------------------------------- ### Admin Interface - Directory and Exact Match Source: https://github.com/esp32async/espasyncwebserver/blob/main/examples/arduino/URIMatcher/README.md Example of using `AsyncURIMatcher::dir` for admin pages and `AsyncURIMatcher::exact` for redirecting to the dashboard. ```cpp // Admin section with authentication server.on(AsyncURIMatcher::dir("/admin"), handleAdminPages); server.on(AsyncURIMatcher::exact("/admin"), redirectToAdminDashboard); ``` -------------------------------- ### Run the Hosted Server and Test with Curl Source: https://github.com/esp32async/espasyncwebserver/blob/main/docs/hosted-build.md Make the compiled host executable runnable and start the server. Then, use curl to send a request to the local server and verify the response. ```bash chmod +x .ci/arduino-emulator-build/out/espasyncwebserver_host .ci/arduino-emulator-build/out/espasyncwebserver_host ``` ```bash curl http://localhost:8080/ ``` -------------------------------- ### Setup Global and Class Request Handlers Source: https://github.com/esp32async/espasyncwebserver/blob/main/docs/setup.md Demonstrates attaching both global functions and class methods as request handlers to an AsyncWebServer instance. Ensure necessary headers are included. ```cpp #include #include #include #include void handleRequest(AsyncWebServerRequest *request){} class WebClass { public : AsyncWebServer classWebServer = AsyncWebServer(81); WebClass(){}; void classRequest (AsyncWebServerRequest *request){} void begin(){ // attach global request handler classWebServer.on("/example", HTTP_ALL, handleRequest); // attach class request handler classWebServer.on("/example", HTTP_ALL, std::bind(&WebClass::classRequest, this, std::placeholders::_1)); } }; AsyncWebServer globalWebServer(80); WebClass webClassInstance; void setup() { // attach global request handler globalWebServer.on("/example", HTTP_ALL, handleRequest); // attach class request handler globalWebServer.on("/example", HTTP_ALL, std::bind(&WebClass::classRequest, webClassInstance, std::placeholders::_1)); } void loop() { } ``` -------------------------------- ### GET, POST, and FILE Parameters Source: https://github.com/esp32async/espasyncwebserver/blob/main/docs/requests.md Methods for retrieving and checking the existence of GET, POST, and FILE parameters from a request. ```APIDOC ### GET, POST and FILE parameters ```cpp // List all parameters int params = request->params(); for(int i=0;igetParam(i); if(p->isFile()){ 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 { Serial.printf("GET[%s]: %s\n", p->name().c_str(), p->value().c_str()); } } // Check if GET parameter exists if(request->hasParam("download")) AsyncWebParameter* p = request->getParam("download"); // Check if POST (but not File) parameter exists if(request->hasParam("download", true)) AsyncWebParameter* p = request->getParam("download", true); // Check if FILE was uploaded if(request->hasParam("download", true, true)) AsyncWebParameter* p = request->getParam("download", true, true); // List all parameters (Compatibility) int args = request->args(); for(int i=0;iargName(i).c_str(), request->arg(i).c_str()); } // Check if parameter exists (Compatibility) if(request->hasArg("download")) String arg = request->arg("download"); ``` See the [Params example here](https://github.com/ESP32Async/ESPAsyncWebServer/blob/master/examples/arduino/Params/Params.ino). ``` -------------------------------- ### Explicit AsyncURIMatcher Syntax Examples Source: https://github.com/esp32async/espasyncwebserver/blob/main/examples/arduino/URIMatcher/README.md Shows how to explicitly define routing rules using the `AsyncURIMatcher` class with specific matching flags. ```cpp // Exact matching only server.on(AsyncURIMatcher("/path", URIMatchExact), handler); ``` ```cpp // Prefix matching only server.on(AsyncURIMatcher("/api", URIMatchPrefix), handler); ``` ```cpp // Combined flags server.on(AsyncURIMatcher("/api", URIMatchPrefix | URIMatchCaseInsensitive), handler); ``` -------------------------------- ### Auto-Detection URL Matching Examples Source: https://github.com/esp32async/espasyncwebserver/blob/main/examples/arduino/URIMatcher/README.md These examples demonstrate how ESPAsyncWebServer can automatically detect and match URLs based on exact paths, folder structures, prefixes, and file extensions. ```plaintext http://192.168.4.1/auto ``` ```plaintext http://192.168.4.1/auto/sub ``` ```plaintext http://192.168.4.1/wildcard-test ``` ```plaintext http://192.168.4.1/auto-images/photo.png ``` -------------------------------- ### REST API Design - Versioning Source: https://github.com/esp32async/espasyncwebserver/blob/main/examples/arduino/URIMatcher/README.md Example of using `AsyncURIMatcher::prefix` to handle API versioning. ```cpp // API versioning server.on(AsyncURIMatcher::prefix("/api/v1"), handleAPIv1); server.on(AsyncURIMatcher::prefix("/api/v2"), handleAPIv2); ``` -------------------------------- ### List and Check Request Parameters Source: https://github.com/esp32async/espasyncwebserver/wiki/Home Iterate through all available parameters (GET, POST, FILE) or check for specific ones. Use the compatibility methods for older argument handling. ```cpp int params = request->params(); for(int i=0;igetParam(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 { Serial.printf("GET[%s]: %s\n", p->name().c_str(), p->value().c_str()); } } //Check if GET parameter exists if(request->hasParam("download")) AsyncWebParameter* p = request->getParam("download"); //Check if POST (but not File) parameter exists if(request->hasParam("download", true)) AsyncWebParameter* p = request->getParam("download", true); //Check if FILE was uploaded if(request->hasParam("download", true, true)) AsyncWebParameter* p = request->getParam("download", true, true); //List all parameters (Compatibility) int args = request->args(); for(int i=0;iargName(i).c_str(), request->arg(i).c_str()); } //Check if parameter exists (Compatibility) if(request->hasArg("download")) String arg = request->arg("download"); ``` -------------------------------- ### Case Insensitive URL Matching Examples Source: https://github.com/esp32async/espasyncwebserver/blob/main/examples/arduino/URIMatcher/README.md Demonstrates matching URLs regardless of case, useful for flexible routing. ```plaintext http://192.168.4.1/case ``` ```plaintext http://192.168.4.1/CASE ``` ```plaintext http://192.168.4.1/CaSe ``` -------------------------------- ### Combined Flags URL Matching Examples Source: https://github.com/esp32async/espasyncwebserver/blob/main/examples/arduino/URIMatcher/README.md Illustrates combining different matching flags like prefix and case-insensitivity for complex routing scenarios. ```plaintext http://192.168.4.1/mixedcase-test ``` ```plaintext http://192.168.4.1/MIXEDCASE/sub ``` -------------------------------- ### Setup AsyncEventSource Server Source: https://github.com/esp32async/espasyncwebserver/blob/main/docs/eventsource.md Configure the AsyncEventSource plugin on the server. Handles new connections by sending an initial message and sets a reconnect delay. Events can be sent from the loop based on a trigger. ```cpp AsyncWebServer server(80); AsyncEventSource events("/events"); void setup(){ // setup ...... events.onConnect([](AsyncEventSourceClient *client){ if(client->lastId()){ Serial.printf("Client reconnected! Last message ID that it got is: %u\n", client->lastId()); } //send event with message "hello!", id current millis // and set reconnect delay to 1 second client->send("hello!",NULL,millis(),1000); }); server.addHandler(&events); // setup ...... } void loop(){ if(eventTriggered){ // your logic here //send event "myevent" events.send("my event content","myevent",millis()); } } ``` -------------------------------- ### Auto-Detection Routing Examples Source: https://github.com/esp32async/espasyncwebserver/blob/main/docs/routing.md Demonstrates traditional string-based routing using auto-detection. These routes automatically adapt to exact, prefix, or extension matching based on the pattern. ```cpp // Auto-detection with exact + folder matching server.on("/api", handler); // Matches /api AND /api/anything server.on("/login", handler); // Matches /login AND /login/sub // Auto-detection with prefix matching server.on("/prefix*", handler); // Matches /prefix, /prefix-test, /prefix/sub // Auto-detection with extension matching server.on("/images/*.jpg", handler); // Matches /images/pic.jpg, /images/sub/pic.jpg ``` -------------------------------- ### Traditional String-based Routing Examples Source: https://github.com/esp32async/espasyncwebserver/blob/main/examples/arduino/URIMatcher/README.md Demonstrates automatic route detection using simple string patterns. The server infers the matching strategy (exact, prefix, extension) from the pattern. ```cpp // Auto-detection with exact + folder matching server.on("/api", handler); // Matches /api AND /api/anything server.on("/login", handler); // Matches /login AND /login/sub ``` ```cpp // Auto-detection with prefix matching server.on("/prefix*", handler); // Matches /prefix, /prefix-test, /prefix/sub ``` ```cpp // Auto-detection with extension matching server.on("/images/*.jpg", handler); // Matches /images/pic.jpg, /images/sub/pic.jpg ``` -------------------------------- ### Factory Function Routing Examples Source: https://github.com/esp32async/espasyncwebserver/blob/main/docs/routing.md Illustrates explicit routing control using factory functions from AsyncURIMatcher. This provides clear definitions for exact, prefix, directory, extension, case-insensitive, and regex matching. ```cpp // Exact matching only (matches "/login" but NOT "/login/sub") server.on(AsyncURIMatcher::exact("/login"), handler); // Prefix matching (matches "/api", "/api/v1", "/api-test") server.on(AsyncURIMatcher::prefix("/api"), handler); // Directory matching (matches "/admin/users" but NOT "/admin") // Requires trailing slash in URL conceptually server.on(AsyncURIMatcher::dir("/admin"), handler); // Extension matching server.on(AsyncURIMatcher::ext("/images/*.jpg"), handler); // Case insensitive matching server.on(AsyncURIMatcher::exact("/case", AsyncURIMatcher::CaseInsensitive), handler); // matches "/case", "/CASE", "/CaSe" // Regular Expression (requires -D ASYNCWEBSERVER_REGEX) #ifdef ASYNCWEBSERVER_REGEX server.on(AsyncURIMatcher::regex("^/user/([0-9]+)$"), handler); #endif ``` -------------------------------- ### SSE Performance Metrics Source: https://github.com/esp32async/espasyncwebserver/wiki/Home Example performance metrics for Server-Sent Events (SSE) with AsyncTCP and AsyncTCPSock, showing events per second and messages discarded. ```text // With AsyncTCP, with 10 workers: no message discarded from the queue // // Total: 2038 events, 509.50 events / second // Total: 2120 events, 530.00 events / second // Total: 2119 events, 529.75 events / second // Total: 2038 events, 509.50 events / second // Total: 2037 events, 509.25 events / second // Total: 2119 events, 529.75 events / second // Total: 2119 events, 529.75 events / second // Total: 2120 events, 530.00 events / second // Total: 2038 events, 509.50 events / second // Total: 2038 events, 509.50 events / second // // With AsyncTCPSock, with 10 workers: no message discarded from the queue // // Total: 2038 events, 509.50 events / second // Total: 2120 events, 530.00 events / second // Total: 2119 events, 529.75 events / second // Total: 2038 events, 509.50 events / second // Total: 2037 events, 509.25 events / second // Total: 2119 events, 529.75 events / second // Total: 2119 events, 529.75 events / second // Total: 2120 events, 530.00 events / second // Total: 2038 events, 509.50 events / second // Total: 2038 events, 509.50 events / second ``` -------------------------------- ### Setup EventSource Client in Browser Source: https://github.com/esp32async/espasyncwebserver/wiki/Home Implement the client-side logic in JavaScript to connect to the EventSource endpoint and handle different event types ('open', 'error', 'message', custom events). This allows for real-time, one-way communication from the server. ```javascript if (!!window.EventSource) { var source = new EventSource("/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 ); } ``` -------------------------------- ### Case Insensitive Exact Match Example Source: https://github.com/esp32async/espasyncwebserver/blob/main/examples/arduino/URIMatcher/README.md Demonstrates case-insensitive exact URL matching. Use this when the URL path should match exactly but without regard to character casing. ```cpp AsyncURIMatcher::exact("/case", AsyncURIMatcher::CaseInsensitive) ``` -------------------------------- ### Setup EventSource Client in Browser Source: https://github.com/esp32async/espasyncwebserver/blob/main/docs/eventsource.md JavaScript code to establish an EventSource connection to the server's /events endpoint. It includes handlers for connection open, errors, and specific message events like 'message' and 'myevent'. ```javascript if (!!window.EventSource) { var source = new EventSource("/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, ); } ``` -------------------------------- ### Usage of Custom Rewrite Source: https://github.com/esp32async/espasyncwebserver/blob/main/docs/routing.md Demonstrates how to add a custom rewrite rule to the server using the previously defined OneParamRewrite class. This example rewrites a URL with a frequency parameter. ```cpp server.addRewrite( new OneParamRewrite("/radio/{frequence}", "/radio?f={frequence}") ); ``` -------------------------------- ### OTA Update Start Callback Source: https://github.com/esp32async/espasyncwebserver/wiki/Home Defines a callback function for the start of an Over-The-Air (OTA) update. This example cleans SPIFFS, disables websockets, and notifies clients. ```cpp // 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(); }); ``` -------------------------------- ### Set Last-Modified Header for Static Files Source: https://github.com/esp32async/espasyncwebserver/wiki/Home Enable 304 Not Modified responses by setting the Last-Modified header. This example shows initial setup and dynamic updates. ```cpp // Update the date modified string every time files are updated server.serveStatic("/", SPIFFS, "/www/").setLastModified("Mon, 20 Jun 2016 14:00:00 GMT"); //*** Change last modified value at a later stage *** // During setup - read last modified value from config or EEPROM String date_modified = loadDateModified(); AsyncStaticWebHandler* handler = &server.serveStatic("/", SPIFFS, "/www/"); handler->setLastModified(date_modified); // At a later event when files are updated String date_modified = getNewDateModfied(); saveDateModified(date_modified); // Save for next reset handler->setLastModified(date_modified); ``` -------------------------------- ### Iterate and Get Request Parameters Source: https://github.com/esp32async/espasyncwebserver/blob/main/docs/requests.md Access all GET, POST, and FILE parameters sent with the request by iterating through them. Check parameter type using isFile() and isPost(). Compatibility functions are also available. ```cpp //List all parameters int params = request->params(); for(int i=0;igetParam(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 { Serial.printf("GET[%s]: %s\n", p->name().c_str(), p->value().c_str()); } } //Check if GET parameter exists if(request->hasParam("download")) AsyncWebParameter* p = request->getParam("download"); //Check if POST (but not File) parameter exists if(request->hasParam("download", true)) AsyncWebParameter* p = request->getParam("download", true); //Check if FILE was uploaded if(request->hasParam("download", true, true)) AsyncWebParameter* p = request->getParam("download", true, true); ``` ```cpp //List all parameters (Compatibility) int args = request->args(); for(int i=0;iargName(i).c_str(), request->arg(i).c_str()); } //Check if parameter exists (Compatibility) if(request->hasArg("download")) String arg = request->arg("download"); ``` -------------------------------- ### Configure and Build Host Executable Source: https://github.com/esp32async/espasyncwebserver/blob/main/docs/hosted-build.md Configure the CMake project for the Arduino Emulator and then build the `espasyncwebserver_host` executable. This command uses Ninja as the generator and specifies the output directory. ```bash # Configure cmake -S examples/arduino_emulator \ -B .ci/arduino-emulator-build/out \ -G Ninja # Build the host executable cmake --build .ci/arduino-emulator-build/out \ --target espasyncwebserver_host \ --parallel ``` -------------------------------- ### Serve Files from a Directory Source: https://github.com/esp32async/espasyncwebserver/wiki/Home Sets up the server to serve all files within a specified SPIFFS directory. Can define a default file for root requests. ```cpp // Serve files in directory "/www/" when request url starts with "/" // Request to the root or none existing files will try to server the default // file name "index.htm" if exists server.serveStatic("/", SPIFFS, "/www/"); // Server with different default file server.serveStatic("/", SPIFFS, "/www/").setDefaultFile("default.html"); ``` -------------------------------- ### Respond with File Content Source: https://github.com/esp32async/espasyncwebserver/blob/main/docs/responses.md Serve files from SPIFFS or LittleFS. Options include default content type, specific text type, or initiating a download. ```cpp //Send index.htm with default content type from SPIFFS request->send(SPIFFS, "/index.htm"); //Send index.htm as text from SPIFFS request->send(SPIFFS, "/index.htm", "text/plain"); //Download index.htm from SPIFFS request->send(SPIFFS, "/index.htm", String(), true); //Send index.htm with default content type from LittleFS request->send(LittleFS, "/index.htm"); //Send index.htm as text from LittleFS request->send(LittleFS, "/index.htm", "text/plain"); //Download index.htm from LittleFS request->send(LittleFS, "/index.htm", String(), true); ``` -------------------------------- ### Direct Access to WebSocket Message Buffer Source: https://github.com/esp32async/espasyncwebserver/blob/main/docs/websockets.md Example of creating and populating a WebSocket message buffer directly for sending. ```APIDOC ### Direct Access to Web Socket Message Buffer This allows direct manipulation of the message buffer before sending, useful for preventing data duplication. The example demonstrates creating a buffer, populating it with JSON data, and then sending it. ```cpp void sendDataWs(AsyncWebSocketClient * client) { JsonDocument doc; doc["a"] = "abc"; doc["b"] = "abcd"; doc["c"] = "abcde"; doc["d"] = "abcdef"; doc["e"] = "abcdefg"; size_t len = measureJson(doc); AsyncWebSocketMessageBuffer * buffer = ws.makeBuffer(len); // Creates a buffer of size (len + 1) if (buffer) { serializeJson(doc, (char *)buffer->get(), len + 1); if (client) { client->text(buffer); } else { ws.textAll(buffer); } } } ``` ``` -------------------------------- ### Respond with File and Extra Headers Source: https://github.com/esp32async/espasyncwebserver/blob/main/docs/responses.md Serve files from storage with custom headers. The response object needs to be initialized before adding headers and sending. ```cpp //Send index.htm with default content type from SPIFFS AsyncWebServerResponse *response = request->beginResponse(SPIFFS, "/index.htm"); //Send index.htm as text from SPIFFS AsyncWebServerResponse *response = request->beginResponse(SPIFFS, "/index.htm", "text/plain"); //Download index.htm from SPIFFS AsyncWebServerResponse *response = request->beginResponse(SPIFFS, "/index.htm", String(), true); //Send index.htm with default content type from LittleFS AsyncWebServerResponse *response = request->beginResponse(LittleFS, "/index.htm"); //Send index.htm as text from LittleFS AsyncWebServerResponse *response = request->beginResponse(LittleFS, "/index.htm", "text/plain"); //Download index.htm from LittleFS AsyncWebServerResponse *response = request->beginResponse(LittleFS, "/index.htm", String(), true); response->addHeader("Server","ESP Async Web Server"); request->send(response); ``` -------------------------------- ### Get Specific Header by Name Source: https://github.com/esp32async/espasyncwebserver/wiki/Home Check if a specific header exists and retrieve its value. This method is compatible with older versions. ```cpp //get specific header by name if(request->hasHeader("MyHeader")){ const AsyncWebHeader* h = request->getHeader("MyHeader"); Serial.printf("MyHeader: %s\n", h->value().c_str()); } ``` -------------------------------- ### REST API Design - Resource Endpoints Source: https://github.com/esp32async/espasyncwebserver/blob/main/examples/arduino/URIMatcher/README.md Example of using `AsyncURIMatcher::regex` to handle resource endpoints with captured IDs. ```cpp // Resource endpoints with IDs server.on(AsyncURIMatcher::regex("^/api/users/([0-9]+)$"), handleUserById); server.on(AsyncURIMatcher::regex("^/api/posts/([0-9]+)/comments$"), handlePostComments); ``` -------------------------------- ### Enable ASYNCWEBSERVER_REGEX for Arduino IDE Source: https://github.com/esp32async/espasyncwebserver/wiki/Home Instructions for enabling the ASYNCWEBSERVER_REGEX build flag in the Arduino IDE by modifying platform.local.txt. This enables regex support for path variables. ```text compiler.cpp.extra_flags=-DASYNCWEBSERVER_REGEX ``` -------------------------------- ### Serve Static Files with Authentication Source: https://github.com/esp32async/espasyncwebserver/wiki/Home Configures the server to serve static files from a directory with basic HTTP authentication. ```cpp server .serveStatic("/", SPIFFS, "/www/") .setDefaultFile("default.html") .setAuthentication("user", "pass"); ``` -------------------------------- ### Prefix Matching with AsyncURIMatcher::prefix() Source: https://github.com/esp32async/espasyncwebserver/blob/main/examples/arduino/URIMatcher/README.md Uses AsyncURIMatcher::prefix() to match URLs that start with the specified pattern. Includes subpaths. ```cpp server.on(AsyncURIMatcher::prefix("/service"), HTTP_GET, [](AsyncWebServerRequest *request){ request->send(200, "text/plain", "Matched /service prefix"); }); ``` ```cpp server.on(AsyncURIMatcher::prefix("/factory/prefix"), HTTP_GET, [](AsyncWebServerRequest *request){ request->send(200, "text/plain", "Matched /factory/prefix prefix"); }); ``` -------------------------------- ### Custom Static File Handling Source: https://github.com/esp32async/espasyncwebserver/wiki/Home Implement custom logic for serving static files, useful when files are too large for standard handling and might cause ESP crashes. This example shows how to set up a not-found handler to manage static file serving. ```cpp bool handleStaticFile(AsyncWebServerRequest *request) { String path = STATIC_FILES_PREFIX + request->url(); if (path.endsWith("/")) path += F("index.html"); String contentType = getContentType(path); String pathWithGz = path + ".gz"; if (SPIFFS.exists(pathWithGz) || SPIFFS.exists(path)) { bool gzipped = false; if (SPIFFS.exists(pathWithGz)) { gzipped = true; path += ".gz"; } // TODO serve the file return true; } return false; } webServer.onNotFound([](AsyncWebServerRequest *request) { if (handleStaticFile(request)) return; request->send(404); }); ``` -------------------------------- ### Auto-Detection: Prefix Match Source: https://github.com/esp32async/espasyncwebserver/blob/main/examples/arduino/URIMatcher/README.md Auto-detects a prefix match when the URI pattern ends with a wildcard '*'. Matches any URI starting with the specified prefix. ```cpp server.on("/wildcard*", HTTP_GET, [](AsyncWebServerRequest *request){ request->send(200, "text/plain", "Matched wildcard*"); }); ``` ```cpp server.on("/api/*", HTTP_GET, [](AsyncWebServerRequest *request){ request->send(200, "text/plain", "Matched api/*"); }); ``` ```cpp server.on("/files/*", HTTP_GET, [](AsyncWebServerRequest *request){ request->send(200, "text/plain", "Matched files/*"); }); ``` -------------------------------- ### Respond with File and Templates Source: https://github.com/esp32async/espasyncwebserver/blob/main/docs/responses.md Serve files containing templates from storage, processed by a provided function. Ensure the processor function is defined and the file content uses template placeholders. ```cpp String processor(const String& var) { if(var == "HELLO_FROM_TEMPLATE") return F("Hello world!"); return String(); } // ... //Send index.htm with template processor function from SPIFFS request->send(SPIFFS, "/index.htm", String(), false, processor); //Send index.htm with template processor function from LittleFS request->send(LittleFS, "/index.htm", String(), false, processor); ``` -------------------------------- ### Get Specific Header by Name (Compatibility) Source: https://github.com/esp32async/espasyncwebserver/wiki/Home Check if a specific header exists and retrieve its value using compatibility functions. This method is compatible with older versions. ```cpp //get specific header by name (Compatibility) if(request->hasHeader("MyHeader")){ Serial.printf("MyHeader: %s\n", request->header("MyHeader").c_str()); } ``` -------------------------------- ### Iterate and Get Request Headers Source: https://github.com/esp32async/espasyncwebserver/blob/main/docs/requests.md Loop through all received headers to print their names and values, or retrieve a specific header by its name. Compatibility functions are also provided. ```cpp //List all collected headers int headers = request->headers(); int i; for(i=0;igetHeader(i); Serial.printf("HEADER[%s]: %s\n", h->name().c_str(), h->value().c_str()); } //get specific header by name if(request->hasHeader("MyHeader")){ const AsyncWebHeader* h = request->getHeader("MyHeader"); Serial.printf("MyHeader: %s\n", h->value().c_str()); } ``` ```cpp //List all collected headers (Compatibility) int headers = request->headers(); int i; for(i=0;iheaderName(i).c_str(), request->header(i).c_str()); } //get specific header by name (Compatibility) if(request->hasHeader("MyHeader")){ Serial.printf("MyHeader: %s\n", request->header("MyHeader").c_str()); } ``` -------------------------------- ### Define Route with Regex Path Variable Source: https://github.com/esp32async/espasyncwebserver/blob/main/docs/requests.md Create a route that matches a URL pattern with a specific parameter, such as an integer sensor ID. Ensure the ASYNCWEBSERVER_REGEX build flag is defined to enable regex support. This adds approximately 100k to the binary size. ```cpp server.on("^\/sensor\/([0-9]+)$", HTTP_GET, [] (AsyncWebServerRequest *request) { String sensorId = request->pathArg(0); }); ``` -------------------------------- ### Case Insensitive Regex Match Example Source: https://github.com/esp32async/espasyncwebserver/blob/main/examples/arduino/URIMatcher/README.md Shows how to perform case-insensitive matching using regular expressions. This is useful for flexible pattern matching where case should not matter. ```cpp AsyncURIMatcher::regex("^/factory/search/(.+)$", AsyncURIMatcher::CaseInsensitive) ``` -------------------------------- ### Configure Authentication with AsyncAuthenticationMiddleware Source: https://github.com/esp32async/espasyncwebserver/blob/main/docs/middleware.md Set up AsyncAuthenticationMiddleware for global or per-handler authentication. Supports DIGEST authentication type and allows customization of realm, username, password, and failure message. Generates hash for optimization. ```cpp AsyncAuthenticationMiddleware authMiddleware; // [...] authMiddleware.setAuthType(AsyncAuthType::AUTH_DIGEST); authMiddleware.setRealm("My app name"); authMiddleware.setUsername("admin"); authMiddleware.setPassword("admin"); authMiddleware.setAuthFailureMessage("Authentication failed"); authMiddleware.generateHash(); // optimization to avoid generating the hash at each request // [...] server.addMiddleware(&authMiddleware); // globally add authentication to the server // [...] myHandler.addMiddleware(&authMiddleware); // add authentication to a specific handler ``` -------------------------------- ### File Upload Handling Source: https://github.com/esp32async/espasyncwebserver/blob/main/docs/requests.md Callback function to handle file uploads, processing file data in chunks and identifying the start, data transfer, and end of the upload. ```APIDOC ## FILE Upload handling ```cpp void handleUpload(AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final){ if(!index){ Serial.printf("UploadStart: %s\n", filename.c_str()); } for(size_t i=0; isetCacheControl("max-age=30"); ```