mirror of
https://github.com/yhirose/cpp-httplib.git
synced 2026-06-10 16:47:14 +00:00
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).
2.8 KiB
2.8 KiB
title, order, status
| title | order | status |
|---|---|---|
| S11. Pre-request handlerでルート単位の認証を行う | 30 | draft |
S09. 全ルートに共通の前処理をするで紹介した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を使って判断してください。
ルートごとに認証を切り替える
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でハンドラ間データを渡すを参照してください。