|
| 1 | +# AsyncURIMatcher Example |
| 2 | + |
| 3 | +This example demonstrates the comprehensive URI matching capabilities of the ESPAsyncWebServer library using the `AsyncURIMatcher` class. |
| 4 | + |
| 5 | +## Overview |
| 6 | + |
| 7 | +The `AsyncURIMatcher` class provides flexible and powerful URL routing mechanisms that go beyond simple string matching. It supports various matching strategies that can be combined to create sophisticated routing rules. |
| 8 | + |
| 9 | +**Important**: When using plain strings (not `AsyncURIMatcher` objects), the library uses auto-detection (`URIMatchAuto`) which analyzes the URI pattern and applies appropriate matching rules. This is **not** simple exact matching - it combines exact and folder matching by default! |
| 10 | + |
| 11 | +## Auto-Detection Behavior |
| 12 | + |
| 13 | +When you pass a plain string or `const char*` to `server.on()`, the `URIMatchAuto` flag is used, which: |
| 14 | + |
| 15 | +1. **Empty URI**: Matches everything |
| 16 | +2. **Ends with `*`**: Becomes prefix match (`URIMatchPrefix`) |
| 17 | +3. **Contains `/*.ext`**: Becomes extension match (`URIMatchExtension`) |
| 18 | +4. **Starts with `^` and ends with `$`**: Becomes regex match (if enabled) |
| 19 | +5. **Everything else**: Becomes **both** exact and folder match (`URIMatchPrefixFolder | URIMatchExact`) |
| 20 | + |
| 21 | +This means traditional string-based routes like `server.on("/path", handler)` will match: |
| 22 | +- `/path` (exact match) |
| 23 | +- `/path/anything` (folder match) |
| 24 | + |
| 25 | +But will **NOT** match `/path-suffix` (prefix without folder separator). |
| 26 | + |
| 27 | +## Features Demonstrated |
| 28 | + |
| 29 | +### 1. **Auto-Detection (Traditional Behavior)** |
| 30 | +- When using plain strings, automatically detects the appropriate matching strategy |
| 31 | +- Default behavior: combines exact and folder matching |
| 32 | +- Special patterns: `*` suffix → prefix, `/*.ext` → extension, regex patterns |
| 33 | +- Use cases: Traditional ESP32 web server behavior with enhanced capabilities |
| 34 | +- Examples: `/path` matches both `/path` and `/path/sub` |
| 35 | + |
| 36 | +### 2. **Exact Matching** |
| 37 | +- Matches only the exact URL specified |
| 38 | +- Use cases: API endpoints, specific pages |
| 39 | +- Examples: `/exact`, `/login`, `/dashboard` |
| 40 | + |
| 41 | +### 3. **Prefix Matching** |
| 42 | +- Matches URLs that start with the specified pattern |
| 43 | +- Use cases: API versioning, module grouping |
| 44 | +- Examples: `/api*` matches `/api/users`, `/api/posts`, etc. |
| 45 | + |
| 46 | +### 4. **Folder/Directory Matching** |
| 47 | +- Matches URLs under a specific directory path |
| 48 | +- Use cases: Admin sections, organized content |
| 49 | +- Examples: `/admin/` matches `/admin/users`, `/admin/settings` |
| 50 | + |
| 51 | +### 5. **Extension Matching** |
| 52 | +- Matches files with specific extensions under a path |
| 53 | +- Use cases: Static file serving, file type handlers |
| 54 | +- Examples: `/images/*.jpg` matches any `.jpg` file under `/images/` |
| 55 | + |
| 56 | +### 6. **Case Insensitive Matching** |
| 57 | +- Matches URLs regardless of character case |
| 58 | +- Use cases: User-friendly URLs, legacy support |
| 59 | +- Examples: `/CaSe` matches `/case`, `/CASE`, etc. |
| 60 | + |
| 61 | +### 7. **Regular Expression Matching** |
| 62 | +- Advanced pattern matching using regex (requires `ASYNCWEBSERVER_REGEX`) |
| 63 | +- Use cases: Complex URL patterns, parameter extraction |
| 64 | +- Examples: `/user/([0-9]+)` matches `/user/123` and captures the ID |
| 65 | + |
| 66 | +### 8. **Combined Flags** |
| 67 | +- Multiple matching strategies can be combined |
| 68 | +- Use cases: Flexible routing requirements |
| 69 | +- Examples: Case-insensitive prefix matching |
| 70 | + |
| 71 | +## Usage Patterns |
| 72 | + |
| 73 | +### Traditional String-based Routing (Auto-Detection) |
| 74 | +```cpp |
| 75 | +// Auto-detection with exact + folder matching |
| 76 | +server.on("/api", handler); // Matches /api AND /api/anything |
| 77 | +server.on("/login", handler); // Matches /login AND /login/sub |
| 78 | + |
| 79 | +// Auto-detection with prefix matching |
| 80 | +server.on("/prefix*", handler); // Matches /prefix, /prefix-test, /prefix/sub |
| 81 | + |
| 82 | +// Auto-detection with extension matching |
| 83 | +server.on("/images/*.jpg", handler); // Matches /images/pic.jpg, /images/sub/pic.jpg |
| 84 | +``` |
| 85 | + |
| 86 | +### Explicit AsyncURIMatcher Syntax |
| 87 | +### Explicit AsyncURIMatcher Syntax |
| 88 | +```cpp |
| 89 | +// Exact matching only |
| 90 | +server.on(AsyncURIMatcher("/path", URIMatchExact), handler); |
| 91 | + |
| 92 | +// Prefix matching only |
| 93 | +server.on(AsyncURIMatcher("/api", URIMatchPrefix), handler); |
| 94 | + |
| 95 | +// Combined flags |
| 96 | +server.on(AsyncURIMatcher("/api", URIMatchPrefix | URIMatchCaseInsensitive), handler); |
| 97 | +``` |
| 98 | + |
| 99 | +### Factory Functions |
| 100 | +```cpp |
| 101 | +// More readable and expressive |
| 102 | +server.on(AsyncURIMatcher::exact("/login"), handler); |
| 103 | +server.on(AsyncURIMatcher::prefix("/api"), handler); |
| 104 | +server.on(AsyncURIMatcher::dir("/admin"), handler); |
| 105 | +server.on(AsyncURIMatcher::ext("/images/*.jpg"), handler); |
| 106 | +server.on(AsyncURIMatcher::iExact("/case"), handler); |
| 107 | + |
| 108 | +#ifdef ASYNCWEBSERVER_REGEX |
| 109 | +server.on(AsyncURIMatcher::regex("^/user/([0-9]+)$"), handler); |
| 110 | +#endif |
| 111 | +``` |
| 112 | + |
| 113 | +## Available Flags |
| 114 | + |
| 115 | +| Flag | Description | |
| 116 | +|------|-------------| |
| 117 | +| `URIMatchAuto` | Auto-detect match type from pattern (default) | |
| 118 | +| `URIMatchExact` | Exact URL match | |
| 119 | +| `URIMatchPrefix` | Prefix match | |
| 120 | +| `URIMatchPrefixFolder` | Folder prefix match (requires trailing /) | |
| 121 | +| `URIMatchExtension` | File extension match pattern | |
| 122 | +| `URIMatchCaseInsensitive` | Case insensitive matching | |
| 123 | +| `URIMatchRegex` | Regular expression matching (requires ASYNCWEBSERVER_REGEX) | |
| 124 | + |
| 125 | +## Testing the Example |
| 126 | + |
| 127 | +1. **Upload the sketch** to your ESP32/ESP8266 |
| 128 | +2. **Connect to WiFi AP**: `esp-captive` (no password required) |
| 129 | +3. **Navigate to**: `http://192.168.4.1/` |
| 130 | +4. **Explore the examples** by clicking the organized test links |
| 131 | +5. **Monitor Serial output**: Open Serial Monitor to see detailed debugging information for each matched route |
| 132 | + |
| 133 | +### Test URLs Available (All Clickable from Homepage) |
| 134 | + |
| 135 | +**Auto-Detection Examples:** |
| 136 | +- `http://192.168.4.1/auto` (exact + folder match) |
| 137 | +- `http://192.168.4.1/auto/sub` (folder match - same handler!) |
| 138 | +- `http://192.168.4.1/wildcard-test` (auto-detected prefix) |
| 139 | +- `http://192.168.4.1/auto-images/photo.png` (auto-detected extension) |
| 140 | + |
| 141 | +**Factory Method Examples:** |
| 142 | +- `http://192.168.4.1/exact` (AsyncURIMatcher::exact) |
| 143 | +- `http://192.168.4.1/service/status` (AsyncURIMatcher::prefix) |
| 144 | +- `http://192.168.4.1/admin/users` (AsyncURIMatcher::dir) |
| 145 | +- `http://192.168.4.1/images/photo.jpg` (AsyncURIMatcher::ext) |
| 146 | + |
| 147 | +**Case Insensitive Examples:** |
| 148 | +- `http://192.168.4.1/case` (lowercase) |
| 149 | +- `http://192.168.4.1/CASE` (uppercase) |
| 150 | +- `http://192.168.4.1/CaSe` (mixed case) |
| 151 | + |
| 152 | +**Regex Examples (if ASYNCWEBSERVER_REGEX enabled):** |
| 153 | +- `http://192.168.4.1/user/123` (captures numeric ID) |
| 154 | +- `http://192.168.4.1/user/456` (captures numeric ID) |
| 155 | + |
| 156 | +**Combined Flags Examples:** |
| 157 | +- `http://192.168.4.1/mixedcase-test` (prefix + case insensitive) |
| 158 | +- `http://192.168.4.1/MIXEDCASE/sub` (prefix + case insensitive) |
| 159 | + |
| 160 | +### Console Output |
| 161 | + |
| 162 | +Each handler provides detailed debugging information via Serial output: |
| 163 | +``` |
| 164 | +Auto-Detection Match (Traditional) |
| 165 | +Matched URL: /auto |
| 166 | +Uses auto-detection: exact + folder matching |
| 167 | +``` |
| 168 | + |
| 169 | +``` |
| 170 | +Factory Exact Match |
| 171 | +Matched URL: /exact |
| 172 | +Uses AsyncURIMatcher::exact() factory function |
| 173 | +``` |
| 174 | + |
| 175 | +``` |
| 176 | +Regex Match - User ID |
| 177 | +Matched URL: /user/123 |
| 178 | +Captured User ID: 123 |
| 179 | +This regex matches /user/{number} pattern |
| 180 | +``` |
| 181 | + |
| 182 | +## Compilation Options |
| 183 | + |
| 184 | +### Enable Regex Support |
| 185 | +To enable regular expression matching, compile with: |
| 186 | +``` |
| 187 | +-D ASYNCWEBSERVER_REGEX |
| 188 | +``` |
| 189 | + |
| 190 | +In PlatformIO, add to `platformio.ini`: |
| 191 | +```ini |
| 192 | +build_flags = -D ASYNCWEBSERVER_REGEX |
| 193 | +``` |
| 194 | + |
| 195 | +In Arduino IDE, add to your sketch: |
| 196 | +```cpp |
| 197 | +#define ASYNCWEBSERVER_REGEX |
| 198 | +``` |
| 199 | + |
| 200 | +## Performance Considerations |
| 201 | + |
| 202 | +1. **Exact matches** are fastest |
| 203 | +2. **Prefix matches** are very efficient |
| 204 | +3. **Regex matches** are slower but most flexible |
| 205 | +4. **Case insensitive** matching adds minimal overhead |
| 206 | +5. **Auto-detection** adds slight parsing overhead at construction time |
| 207 | + |
| 208 | +## Real-World Applications |
| 209 | + |
| 210 | +### REST API Design |
| 211 | +```cpp |
| 212 | +// API versioning |
| 213 | +server.on(AsyncURIMatcher::prefix("/api/v1"), handleAPIv1); |
| 214 | +server.on(AsyncURIMatcher::prefix("/api/v2"), handleAPIv2); |
| 215 | + |
| 216 | +// Resource endpoints with IDs |
| 217 | +server.on(AsyncURIMatcher::regex("^/api/users/([0-9]+)$"), handleUserById); |
| 218 | +server.on(AsyncURIMatcher::regex("^/api/posts/([0-9]+)/comments$"), handlePostComments); |
| 219 | +``` |
| 220 | + |
| 221 | +### File Serving |
| 222 | +```cpp |
| 223 | +// Serve different file types |
| 224 | +server.on(AsyncURIMatcher::ext("/assets/*.css"), serveCSSFiles); |
| 225 | +server.on(AsyncURIMatcher::ext("/assets/*.js"), serveJSFiles); |
| 226 | +server.on(AsyncURIMatcher::ext("/images/*.jpg"), serveImageFiles); |
| 227 | +``` |
| 228 | + |
| 229 | +### Admin Interface |
| 230 | +```cpp |
| 231 | +// Admin section with authentication |
| 232 | +server.on(AsyncURIMatcher::dir("/admin"), handleAdminPages); |
| 233 | +server.on(AsyncURIMatcher::exact("/admin"), redirectToAdminDashboard); |
| 234 | +``` |
| 235 | + |
| 236 | +## See Also |
| 237 | + |
| 238 | +- [ESPAsyncWebServer Documentation](https://github.com/ESP32Async/ESPAsyncWebServer) |
| 239 | +- [Regular Expression Reference](https://en.cppreference.com/w/cpp/regex) |
| 240 | +- Other examples in the `examples/` directory |
0 commit comments