Files
cpp-httplib/docs-src/pages/ja/cookbook/s11-pre-request.md
yhirose 77bdf7921a 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).
2026-06-09 13:49:56 -04:00

50 lines
2.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
title: "S11. Pre-request handlerでルート単位の認証を行う"
order: 30
status: "draft"
---
[S09. 全ルートに共通の前処理をする](s09-pre-routing)で紹介した`set_pre_routing_handler()`はルーティングの**前**に呼ばれるので、「どのルートにマッチしたか」を知れません。ルートによって認証の有無を変えたい場合は、`set_pre_request_handler()`のほうが便利です。
## Pre-routingとの違い
| フック | 呼ばれるタイミング | ルート情報 | リクエストボディ |
| --- | --- | --- | --- |
| `set_pre_routing_handler` | ルーティングの前 | 取得できない | まだ読まれていない |
| `set_pre_request_handler` | ルーティング後、ルートハンドラの直前 | `req.matched_route`で取得可能 | まだ読まれていない |
Pre-requestハンドラなら、`req.matched_route`に「マッチしたパターン文字列」が入っているので、ルートに応じて処理を変えられます。
Pre-requestハンドラが呼ばれる時点ではボディがまだ読まれていないので、認証に失敗したリクエストなどを、巨大かもしれないボディを読み込む前に拒否できます。その代わり、`req.body`やボディから解析されるフォームフィールドはこの時点では参照できません。ヘッダ・パス・クエリパラメータ・`req.matched_route`を使って判断してください。
## ルートごとに認証を切り替える
```cpp
svr.set_pre_request_handler(
[](const httplib::Request &req, httplib::Response &res) {
// /adminで始まるルートだけ認証を要求
if (req.matched_route.rfind("/admin", 0) == 0) {
auto token = req.get_header_value("Authorization");
if (!is_admin_token(token)) {
res.status = 403;
res.set_content("forbidden", "text/plain");
return httplib::Server::HandlerResponse::Handled;
}
}
return httplib::Server::HandlerResponse::Unhandled;
});
```
`matched_route`はパスパラメーターを展開する**前**のパターン文字列(例: `/admin/users/:id`です。特定の値ではなく、ルート定義のパターンで判定できるので、IDや名前に左右されません。
## 戻り値の意味
Pre-routingハンドラと同じく、`HandlerResponse`を返します。
- `Unhandled`: 通常の処理を続行(ルートハンドラが呼ばれる)
- `Handled`: ここで完了、ルートハンドラはスキップされる
## 認証情報を後続のハンドラに渡す
認証で取り出したユーザー情報などをルートハンドラに渡したいときは、`res.user_data`を使います。詳しくは[S12. `res.user_data`でハンドラ間データを渡す](s12-user-data)を参照してください。