處理流程

Service 先將請求轉換為 salvo 的 Response,然後進入路由匹配階段。

路由匹配階段

路由匹配按照添加的次序,依次按從外到內、從上往下的順序執行過濾器,任何一個過濾器執行失敗,就會被視為匹配失敗。

匹配過程中,存在請求的路徑資訊,隨著匹配的進行,路徑過濾器一旦匹配成功,就會消耗掉它匹配到的路徑。當所有路徑都消耗完畢且匹配的鏈路上沒有過濾器匹配失敗,當前鏈路上最後一個 Router 存在 goal Handler,那麼匹配成功,匹配階段結束,收集匹配所有匹配鏈路上的 Handler 進入執行階段。

如果路徑未消耗完畢,鏈路上過濾器沒報錯,但也不再有子路由可以繼續匹配,則視為當前鏈路匹配失敗,進入下一個路由匹配。

所有的路由都匹配完畢,沒有成功,則進入錯誤捕獲階段。

Handler 執行階段

根據匹配階段收集到的 Handler 列表依次執行 Handler。執行過程中前面的中介軟體可以呼叫 ctrl::call_next() 讓後續的中介軟體先執行,然後再執行自己的邏輯。如果執行過程中出現狀態碼錯誤或轉向,那麼後續的 Handler 將不再執行,此時如果狀態碼是錯誤,並且 ResponseBody 未設定或是 ResBody::Error,則進入錯誤捕獲階段,反之跳過捕獲階段。

錯誤捕獲階段

Catcher 是用於處理錯誤的類型,它也可以添加中介軟體(hoops),錯誤會依次通過 Catcher 裡面的所有 Handler。如果某個 Handler 已經處理了錯誤,不想後續 Handler 繼續執行,可以透過 ctrl.skip_rest() 跳過後續的 Handler,直接結束捕獲階段。

Catcher 預設必須包含一個 Handler 用於作為預設錯誤處理。預設的是 DefaultGoal,你也可以完全自訂自己的 Handler 作為錯誤處理的預設實現。它會根據請求頭要求的 content-type 顯示對應格式的錯誤資訊,支援 jsonxmltexthtml 四種顯示格式。DefaultGoal 也提供了一些顯示設定,例如,預設它在顯示 html 格式時會顯示 salvo 相關連結,就可以呼叫 DefaultGoal::footerDefaultGoal::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;