You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Read request body after route matching and pre-request handler
Previously, for regular handlers the request body was read in routing()
before the route was matched, so the pre-request handler always saw an
already-read body. The ContentReader path, in contrast, ran the
pre-request handler before the body was read. This inconsistency made
it impossible to reject a request (e.g. failed per-route authentication
via req.matched_route) without buffering a potentially large body.
Move the read_content() call into dispatch_request(), after route
matching and the pre-request handler, so both paths behave the same:
route matching -> pre_request_handler -> body read -> handler. A
request rejected by the pre-request handler no longer reads the body
at all; the existing keep-alive drain logic still consumes any framed
body afterwards.
Note: code that referenced req.body or body-derived form fields inside
the pre-request handler will now see an empty body. Inspect headers,
path, query parameters, or matched_route instead.
Also document the handler execution order in README and update the
pre-request cookbook pages (en/ja).
The pre-request handler runs after the route has been matched (so `req.matched_route` and `req.path_params` are available) but **before the request body is read**. This means you can reject a request — for example on a failed authentication or authorization check — without forcing the server to buffer a potentially large body.
> Because the body has not been read yet, `req.body` and form fields parsed from the body are not available in the pre-request handler. Inspect headers, the path, query parameters, or `req.matched_route` instead.
471
+
472
+
### Handler execution order
473
+
474
+
`set_start_handler` runs once when the server starts. For each request, handlers run in the following order:
475
+
476
+
```
477
+
Request received
478
+
│
479
+
├─ pre_routing_handler route not matched yet, body not read
├─ expect_100_continue_handler (when the request has "Expect: 100-continue")
485
+
│
486
+
├─ route matching → req.matched_route is set
487
+
│
488
+
├─ pre_request_handler route matched, body NOT read yet
489
+
│ └─ returns Handled → stop here (route handler is skipped)
490
+
│
491
+
├─ route handler Get/Post/...; the request body is read first
492
+
│
493
+
└─ post_routing_handler after routing completes
494
+
495
+
On a thrown exception → exception_handler
496
+
On an error status (4xx/5xx) → error_handler
497
+
```
498
+
499
+
Use `pre_routing_handler` to reject a request as early as possible, before the route is known. Use `pre_request_handler` for route-specific checks, since `req.matched_route` is available and the body has not been read yet.
500
+
467
501
### Response user data
468
502
469
503
`res.user_data` is a type-safe key-value store that lets pre-routing or pre-request handlers pass arbitrary data to route handlers.
Copy file name to clipboardExpand all lines: docs-src/pages/en/cookbook/s11-pre-request.md
+6-4Lines changed: 6 additions & 4 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -8,13 +8,15 @@ The `set_pre_routing_handler()` from [S09. Add pre-processing to all routes](s09
8
8
9
9
## Pre-routing vs. pre-request
10
10
11
-
| Hook | When it runs | Route info |
12
-
| --- | --- | --- |
13
-
|`set_pre_routing_handler`| Before routing | Not available |
14
-
|`set_pre_request_handler`| After routing, right before the route handler | Available via `req.matched_route`|
11
+
| Hook | When it runs | Route info | Request body |
12
+
| --- | --- | --- | --- |
13
+
|`set_pre_routing_handler`| Before routing | Not available | Not read yet |
14
+
|`set_pre_request_handler`| After routing, right before the route handler | Available via `req.matched_route`| Not read yet |
15
15
16
16
In a pre-request handler, `req.matched_route` holds the **pattern string** that matched. You can vary behavior based on the route definition itself.
17
17
18
+
Because the body has not been read when the pre-request handler runs, you can reject a request — for example on a failed auth check — without consuming a (potentially large) request body. Note that this also means `req.body` and form fields parsed from the body are not available here; inspect headers, the path, query parameters, or `req.matched_route` instead.
0 commit comments