処理フロー

Service はまずリクエストをSalvoの Response に変換し、その後ルーティングマッチング段階に入ります。

ルーティングマッチング段階

ルーティングマッチングは、追加された順序に従い、外側から内側へ、上から下へと順番にフィルターを実行します。いずれかのフィルターが失敗すると、マッチング失敗と見なされます。

マッチングプロセスでは、リクエストのパス情報が存在します。マッチングが進むにつれて、パスフィルターが一度マッチングに成功すると、そのマッチングしたパス部分が消費されます。すべてのパスが消費され、マッチングチェーン上のフィルターが失敗せず、現在のチェーンの最後の Routergoal Handler が存在する場合、マッチング成功となり、マッチング段階が終了します。マッチングしたすべてのチェーン上の Handler を収集し、実行段階へ進みます。

パスが完全に消費されず、チェーン上のフィルターがエラーを起こさないが、さらにマッチングを続けるサブルートが存在しない場合、現在のチェーンのマッチングは失敗と見なされ、次のルートマッチングへ進みます。

すべてのルートのマッチングが完了し、成功しなかった場合、エラーキャプチャ段階へ進みます。

Handler 実行段階

マッチング段階で収集された Handler リストに従い、順番に Handler を実行します。実行プロセスでは、前のミドルウェアが ctrl::call_next() を呼び出すことで、後続のミドルウェアを先に実行し、その後自身のロジックを実行できます。実行中にステータスコードエラーやリダイレクトが発生した場合、後続の Handler は実行されません。この時、ステータスコードがエラーであり、かつ ResponseBody が設定されていないか ResBody::Error である場合、エラーキャプチャ段階へ進みます。それ以外の場合はキャプチャ段階をスキップします。

エラーキャプチャ段階

Catcher はエラーを処理するための型であり、ミドルウェア(hoops)を追加することもできます。エラーは Catcher 内のすべての Handler を順番に通過します。ある Handler がエラーを処理し、後続の Handler の実行を続けたくない場合は、 ctrl.skip_rest() を呼び出して後続の Handler をスキップし、直接キャプチャ段階を終了できます。

Catcher はデフォルトで、デフォルトのエラー処理として機能する1つの Handler を含んでいる必要があります。デフォルトは DefaultGoal です。エラー処理のデフォルト実装として、完全に独自の Handler をカスタマイズすることもできます。これはリクエストヘッダーで要求される content-type に応じて対応する形式のエラーメッセージを表示し、jsonxmltexthtml の4つの表示形式をサポートしています。 DefaultGoal はまた、いくつかの表示設定を提供しています。例えば、デフォルトではHTML形式を表示する際にSalvo関連のリンクを表示しますが、 DefaultGoal::footer または DefaultGoal::with_footer を呼び出して、独自に希望するカスタムフッターに設定することもできます。

Service はSalvoの Response をhyperの Response 型に変換し、最終的にブラウザなどのクライアントに返します。

Salvo リクエストライフサイクル

これは、Salvo WebフレームワークがHTTPリクエストを処理するライフサイクルの視覚的表現と説明です。

flowchart TD
    subgraph MainGraph[Salvoフレームワーク リクエストライフサイクル]
        Start[クライアントリクエスト] --> Convert[ServiceがHTTPリクエストをsalvoのResponseに変換]
        
        %% ルーティングマッチング段階
        subgraph RoutingPhase[1. ルーティングマッチング段階]
            Convert --> Routing[追加順序、外から内、上から下でルートをマッチング]
            Routing --> FilterCheck{フィルターはすべて通過?}
            FilterCheck -->|いいえ| NextRoute[次のルートを試行]
            FilterCheck -->|はい| PathConsume[マッチングしたパス部分を消費]
            PathConsume --> PathCheck{パスは完全に消費され、goal Handlerがある?}
            PathCheck -->|いいえ| SubRouteCheck{マッチングを続けるサブルートがある?}
            SubRouteCheck -->|はい| Routing
            SubRouteCheck -->|いいえ| NextRoute
            NextRoute --> RouteLeft{他にルートは残っている?}
            RouteLeft -->|はい| Routing
            RouteLeft -->|いいえ| NoMatchRoute[ルーティングマッチング失敗]
            PathCheck -->|はい| MatchSuccess[ルーティングマッチング成功]
            MatchSuccess --> CollectHandlers[マッチングチェーン上のすべてのHandlerを収集]
        end
        
        %% Handler実行段階
        subgraph HandlerPhase[2. Handler実行段階]
            CollectHandlers --> ExecHandlers[順番にHandlerを実行]
            ExecHandlers --> ErrorCheck{実行中にエラーまたはリダイレクトが発生?}
            ErrorCheck -->|いいえ| FinishHandlers[すべてのHandler実行完了]
            ErrorCheck -->|はい| StatusCheck{ステータスコードはエラーで、Bodyが未設定またはError?}
            StatusCheck -->|はい| EnterCatcher[エラーキャプチャ段階へ]
            StatusCheck -->|いいえ| SkipCatcher[エラーキャプチャ段階をスキップ]
        end
        
        %% エラーキャプチャ段階
        subgraph CatcherPhase[3. エラーキャプチャ段階]
            EnterCatcher --> CatcherHandlers[CatcherのHandlerを順番に実行]
            NoMatchRoute --> CatcherHandlers
            CatcherHandlers --> DefaultHandler[DefaultGoalまたはカスタムエラー処理]
        end
        
        %% 最終レスポンス
        FinishHandlers --> FinalConvert[Serviceがsalvo Responseをhyper Responseに変換]
        SkipCatcher --> FinalConvert
        DefaultHandler --> FinalConvert
        
        FinalConvert --> End[クライアントにレスポンスを返す]
    end
    
    %% スタイル
    class RoutingPhase,HandlerPhase,CatcherPhase phase;
    class MainGraph mainGraph;
    classDef mainGraph fill:#f5f5f5,stroke:#333,stroke-width:1px;
    classDef phase fill:#e6f3ff,stroke:#333,stroke-width:2px;