Subversion Repositories ESP8266_P1_Meter

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 raymond 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
## What's Demonstrated
12
 
13
This example includes two Arduino sketches:
14
 
15
1. **URIMatcher.ino** - Interactive web-based demonstration with a user-friendly homepage
16
2. **URIMatcherTest.ino** - Comprehensive test suite with automated shell script testing
17
 
18
Both sketches create a WiFi Access Point (`esp-captive`) for easy testing without network configuration.
19
 
20
## Auto-Detection Behavior
21
 
22
When you pass a plain string or `const char*` to `server.on()`, the `URIMatchAuto` flag is used, which:
23
 
24
1. **Empty URI**: Matches everything
25
2. **Ends with `*`**: Becomes prefix match (`URIMatchPrefix`)
26
3. **Contains `/*.ext`**: Becomes extension match (`URIMatchExtension`)
27
4. **Starts with `^` and ends with `$`**: Becomes regex match (if enabled)
28
5. **Everything else**: Becomes **both** exact and folder match (`URIMatchPrefixFolder | URIMatchExact`)
29
 
30
This means traditional string-based routes like `server.on("/path", handler)` will match:
31
 
32
- `/path` (exact match)
33
- `/path/` (folder with trailing slash)
34
- `/path/anything` (folder match)
35
 
36
But will **NOT** match `/path-suffix` (prefix without folder separator).
37
 
38
## Features Demonstrated
39
 
40
### 1. **Auto-Detection (Traditional Behavior)**
41
 
42
Demonstrates how traditional string-based routing automatically combines exact and folder matching.
43
 
44
**Examples in URIMatcher.ino:**
45
 
46
- `/auto` - Matches both `/auto` exactly AND `/auto/sub` as folder
47
- `/wildcard*` - Auto-detects as prefix match (due to trailing `*`)
48
- `/auto-images/*.png` - Auto-detects as extension match (due to `/*.ext` pattern)
49
 
50
**Examples in URIMatcherTest.ino:**
51
 
52
- `/exact` - Matches `/exact`, `/exact/`, and `/exact/sub`
53
- `/api/users` - Matches exact path and subpaths under `/api/users/`
54
- `/*.json` - Matches any `.json` file anywhere
55
- `/*.css` - Matches any `.css` file anywhere
56
 
57
### 2. **Exact Matching (Factory Method)**
58
 
59
Using `AsyncURIMatcher::exact()` matches only the exact URL, **NOT** subpaths.
60
 
61
**Key difference from auto-detection:** `AsyncURIMatcher::exact("/path")` matches **only** `/path`, while `server.on("/path", ...)` matches both `/path` and `/path/sub`.
62
 
63
**Examples in URIMatcher.ino:**
64
 
65
- `AsyncURIMatcher::exact("/exact")` - Matches only `/exact`
66
 
67
**Examples in URIMatcherTest.ino:**
68
 
69
- `AsyncURIMatcher::exact("/factory/exact")` - Matches only `/factory/exact`
70
- Does NOT match `/factory/exact/sub` (404 response)
71
 
72
### 3. **Prefix Matching**
73
 
74
Using `AsyncURIMatcher::prefix()` matches URLs that start with the specified pattern.
75
 
76
**Examples in URIMatcher.ino:**
77
 
78
- `AsyncURIMatcher::prefix("/service")` - Matches `/service`, `/service-test`, `/service/status`
79
 
80
**Examples in URIMatcherTest.ino:**
81
 
82
- `AsyncURIMatcher::prefix("/factory/prefix")` - Matches `/factory/prefix`, `/factory/prefix-test`, `/factory/prefix/sub`
83
- Traditional: `/api/*` - Matches `/api/data`, `/api/v1/posts`
84
- Traditional: `/files/*` - Matches `/files/document.pdf`, `/files/images/photo.jpg`
85
 
86
### 4. **Folder/Directory Matching**
87
 
88
Using `AsyncURIMatcher::dir()` matches URLs under a directory (automatically adds trailing slash).
89
 
90
**Important:** Directory matching requires a trailing slash in the URL - it does NOT match the directory itself.
91
 
92
**Examples in URIMatcher.ino:**
93
 
94
- `AsyncURIMatcher::dir("/admin")` - Matches `/admin/users`, `/admin/settings`
95
- Does NOT match `/admin` without trailing slash
96
 
97
**Examples in URIMatcherTest.ino:**
98
 
99
- `AsyncURIMatcher::dir("/factory/dir")` - Matches `/factory/dir/users`, `/factory/dir/sub/path`
100
- Does NOT match `/factory/dir` itself (404 response)
101
 
102
### 5. **Extension Matching**
103
 
104
Using `AsyncURIMatcher::ext()` matches files with specific extensions.
105
 
106
**Examples in URIMatcher.ino:**
107
 
108
- `AsyncURIMatcher::ext("/images/*.jpg")` - Matches `/images/photo.jpg`, `/images/sub/pic.jpg`
109
 
110
**Examples in URIMatcherTest.ino:**
111
 
112
- `AsyncURIMatcher::ext("/factory/files/*.txt")` - Matches `/factory/files/doc.txt`, `/factory/files/sub/readme.txt`
113
- Does NOT match `/factory/files/doc.pdf` (wrong extension)
114
 
115
### 6. **Case Insensitive Matching**
116
 
117
Using `AsyncURIMatcher::CaseInsensitive` flag matches URLs regardless of character case.
118
 
119
**Examples in URIMatcher.ino:**
120
 
121
- `AsyncURIMatcher::exact("/case", AsyncURIMatcher::CaseInsensitive)` - Matches `/case`, `/CASE`, `/CaSe`
122
 
123
**Examples in URIMatcherTest.ino:**
124
 
125
- Case insensitive exact: `/case/exact`, `/CASE/EXACT`, `/Case/Exact` all work
126
- Case insensitive prefix: `/case/prefix`, `/CASE/PREFIX-test`, `/Case/Prefix/sub` all work
127
- Case insensitive directory: `/case/dir/users`, `/CASE/DIR/admin`, `/Case/Dir/settings` all work
128
- Case insensitive extension: `/case/files/doc.pdf`, `/CASE/FILES/DOC.PDF`, `/Case/Files/Doc.Pdf` all work
129
 
130
### 7. **Regular Expression Matching**
131
 
132
Using `AsyncURIMatcher::regex()` for advanced pattern matching (requires `ASYNCWEBSERVER_REGEX`).
133
 
134
**Examples in URIMatcher.ino:**
135
 
136
```cpp
137
#ifdef ASYNCWEBSERVER_REGEX
138
AsyncURIMatcher::regex("^/user/([0-9]+)$")  // Matches /user/123, captures ID
139
#endif
140
```
141
 
142
**Examples in URIMatcherTest.ino:**
143
 
144
- Traditional regex: `^/user/([0-9]+)$` - Matches `/user/123`, `/user/456`
145
- Traditional regex: `^/blog/([0-9]{4})/([0-9]{2})/([0-9]{2})$` - Matches `/blog/2023/10/15`
146
- Factory regex: `AsyncURIMatcher::regex("^/factory/user/([0-9]+)$")` - Matches `/factory/user/123`
147
- Factory regex with multiple captures: `^/factory/blog/([0-9]{4})/([0-9]{2})/([0-9]{2})$`
148
- Case insensitive regex: `AsyncURIMatcher::regex("^/factory/search/(.+)$", AsyncURIMatcher::CaseInsensitive)`
149
 
150
### 8. **Combined Flags**
151
 
152
Multiple matching strategies can be combined using the `|` operator.
153
 
154
**Examples in URIMatcher.ino:**
155
 
156
- `AsyncURIMatcher::prefix("/MixedCase", AsyncURIMatcher::CaseInsensitive)` - Prefix match that's case insensitive
157
 
158
### 9. **Special Matchers**
159
 
160
**Examples in URIMatcherTest.ino:**
161
 
162
- `AsyncURIMatcher::all()` - Matches all requests (used with POST method as catch-all)
163
 
164
## Usage Patterns
165
 
166
### Traditional String-based Routing (Auto-Detection)
167
 
168
```cpp
169
// Auto-detection with exact + folder matching
170
server.on("/api", handler);          // Matches /api AND /api/anything
171
server.on("/login", handler);        // Matches /login AND /login/sub
172
 
173
// Auto-detection with prefix matching
174
server.on("/prefix*", handler);      // Matches /prefix, /prefix-test, /prefix/sub
175
 
176
// Auto-detection with extension matching
177
server.on("/images/*.jpg", handler); // Matches /images/pic.jpg, /images/sub/pic.jpg
178
```
179
 
180
### Explicit AsyncURIMatcher Syntax
181
 
182
### Explicit AsyncURIMatcher Syntax
183
 
184
```cpp
185
// Exact matching only
186
server.on(AsyncURIMatcher("/path", URIMatchExact), handler);
187
 
188
// Prefix matching only
189
server.on(AsyncURIMatcher("/api", URIMatchPrefix), handler);
190
 
191
// Combined flags
192
server.on(AsyncURIMatcher("/api", URIMatchPrefix | URIMatchCaseInsensitive), handler);
193
```
194
 
195
### Factory Functions
196
 
197
```cpp
198
// More readable and expressive
199
server.on(AsyncURIMatcher::exact("/login"), handler);
200
server.on(AsyncURIMatcher::prefix("/api"), handler);
201
server.on(AsyncURIMatcher::dir("/admin"), handler);
202
server.on(AsyncURIMatcher::ext("/images/*.jpg"), handler);
203
 
204
#ifdef ASYNCWEBSERVER_REGEX
205
server.on(AsyncURIMatcher::regex("^/user/([0-9]+)$"), handler);
206
#endif
207
```
208
 
209
## Available Flags
210
 
211
| Flag                      | Description                                                 |
212
| ------------------------- | ----------------------------------------------------------- |
213
| `URIMatchAuto`            | Auto-detect match type from pattern (default)               |
214
| `URIMatchExact`           | Exact URL match                                             |
215
| `URIMatchPrefix`          | Prefix match                                                |
216
| `URIMatchPrefixFolder`    | Folder prefix match (requires trailing /)                   |
217
| `URIMatchExtension`       | File extension match pattern                                |
218
| `URIMatchCaseInsensitive` | Case insensitive matching                                   |
219
| `URIMatchRegex`           | Regular expression matching (requires ASYNCWEBSERVER_REGEX) |
220
 
221
## Testing the Example
222
 
223
1. **Upload the sketch** to your ESP32/ESP8266
224
2. **Connect to WiFi AP**: `esp-captive` (no password required)
225
3. **Navigate to**: `http://192.168.4.1/`
226
4. **Explore the examples** by clicking the organized test links
227
5. **Monitor Serial output**: Open Serial Monitor to see detailed debugging information for each matched route
228
 
229
### Test URLs Available (All Clickable from Homepage)
230
 
231
**Auto-Detection Examples:**
232
 
233
- `http://192.168.4.1/auto` (exact + folder match)
234
- `http://192.168.4.1/auto/sub` (folder match - same handler!)
235
- `http://192.168.4.1/wildcard-test` (auto-detected prefix)
236
- `http://192.168.4.1/auto-images/photo.png` (auto-detected extension)
237
 
238
**Factory Method Examples:**
239
 
240
- `http://192.168.4.1/exact` (AsyncURIMatcher::exact)
241
- `http://192.168.4.1/service/status` (AsyncURIMatcher::prefix)
242
- `http://192.168.4.1/admin/users` (AsyncURIMatcher::dir)
243
- `http://192.168.4.1/images/photo.jpg` (AsyncURIMatcher::ext)
244
 
245
**Case Insensitive Examples:**
246
 
247
- `http://192.168.4.1/case` (lowercase)
248
- `http://192.168.4.1/CASE` (uppercase)
249
- `http://192.168.4.1/CaSe` (mixed case)
250
 
251
**Regex Examples (if ASYNCWEBSERVER_REGEX enabled):**
252
 
253
- `http://192.168.4.1/user/123` (captures numeric ID)
254
- `http://192.168.4.1/user/456` (captures numeric ID)
255
 
256
**Combined Flags Examples:**
257
 
258
- `http://192.168.4.1/mixedcase-test` (prefix + case insensitive)
259
- `http://192.168.4.1/MIXEDCASE/sub` (prefix + case insensitive)
260
 
261
### Console Output
262
 
263
Each handler provides detailed debugging information via Serial output:
264
 
265
```
266
Auto-Detection Match (Traditional)
267
Matched URL: /auto
268
Uses auto-detection: exact + folder matching
269
```
270
 
271
```
272
Factory Exact Match
273
Matched URL: /exact
274
Uses AsyncURIMatcher::exact() factory function
275
```
276
 
277
```
278
Regex Match - User ID
279
Matched URL: /user/123
280
Captured User ID: 123
281
This regex matches /user/{number} pattern
282
```
283
 
284
## Compilation Options
285
 
286
### Enable Regex Support
287
 
288
To enable regular expression matching, compile with:
289
 
290
```
291
-D ASYNCWEBSERVER_REGEX
292
```
293
 
294
In PlatformIO, add to `platformio.ini`:
295
 
296
```ini
297
build_flags = -D ASYNCWEBSERVER_REGEX
298
```
299
 
300
In Arduino IDE, add to your sketch:
301
 
302
```cpp
303
#define ASYNCWEBSERVER_REGEX
304
```
305
 
306
## Performance Considerations
307
 
308
1. **Exact matches** are fastest
309
2. **Prefix matches** are very efficient
310
3. **Regex matches** are slower but most flexible
311
4. **Case insensitive** matching adds minimal overhead
312
5. **Auto-detection** adds slight parsing overhead at construction time
313
 
314
## Real-World Applications
315
 
316
### REST API Design
317
 
318
```cpp
319
// API versioning
320
server.on(AsyncURIMatcher::prefix("/api/v1"), handleAPIv1);
321
server.on(AsyncURIMatcher::prefix("/api/v2"), handleAPIv2);
322
 
323
// Resource endpoints with IDs
324
server.on(AsyncURIMatcher::regex("^/api/users/([0-9]+)$"), handleUserById);
325
server.on(AsyncURIMatcher::regex("^/api/posts/([0-9]+)/comments$"), handlePostComments);
326
```
327
 
328
### File Serving
329
 
330
```cpp
331
// Serve different file types
332
server.on(AsyncURIMatcher::ext("/assets/*.css"), serveCSSFiles);
333
server.on(AsyncURIMatcher::ext("/assets/*.js"), serveJSFiles);
334
server.on(AsyncURIMatcher::ext("/images/*.jpg"), serveImageFiles);
335
```
336
 
337
### Admin Interface
338
 
339
```cpp
340
// Admin section with authentication
341
server.on(AsyncURIMatcher::dir("/admin"), handleAdminPages);
342
server.on(AsyncURIMatcher::exact("/admin"), redirectToAdminDashboard);
343
```
344
 
345
## See Also
346
 
347
- [ESPAsyncWebServer Documentation](https://github.com/ESP32Async/ESPAsyncWebServer)
348
- [Regular Expression Reference](https://en.cppreference.com/w/cpp/regex)
349
- Other examples in the `examples/` directory