リクエスト中のPanicをキャッチ
Catch Panicは、リクエスト処理中に発生するクラッシュをキャッチするために使用されます。詳細なAPIについてはドキュメントを参照してください。
注意: CatchPanic
を使用するには、Cargo.toml
でcatch-panic
featureを有効にする必要があります:
salvo= { version = "xxx", features = ["catch-panic"] }
ミドルウェアの紹介
CatchPanic
は、ハンドラ内で発生したpanicをキャッチするミドルウェアです。リクエスト処理中にpanicが発生すると、サーバー全体がクラッシュする代わりに、これらのpanicをキャッチし、500 Internal Server Errorをレスポンスに書き込みます。
重要: このミドルウェアは、他のミドルウェアやハンドラ内のpanicを確実にキャッチするために、最初のミドルウェアとして使用する必要があります。
基本的な使い方
use salvo_core::prelude::*;
use salvo_extra::catch_panic::CatchPanic;
#[handler]
async fn hello() {
panic!("panic error!");
}
#[tokio::main]
async fn main() {
let router = Router::new().hoop(CatchPanic::new()).get(hello);
let acceptor = TcpListener::new("0.0.0.0:5800").bind().await;
Server::new(acceptor).serve(router).await;
}
他のフレームワークとの比較 概念の簡単な理解
Axum
Axumでは、Tower
のcatch_panic
ミドルウェアに相当します:
use axum::{
Router,
routing::get,
http::StatusCode,
};
use tower::ServiceBuilder;
use tower_http::catch_panic::CatchPanicLayer;
async fn panic_handler() -> &'static str {
panic!("panic error!");
}
#[tokio::main]
async fn main() {
let app = Router::new()
.route("/", get(panic_handler))
.layer(
ServiceBuilder::new()
.layer(CatchPanicLayer::new())
);
axum::Server::bind(&"0.0.0.0:3000".parse().unwrap())
.serve(app.into_make_service())
.await
.unwrap();
}
Gin (Go)
Go言語のGinフレームワークでは、Recoveryミドルウェアが類似の機能を提供します:
package main
import (
"github.com/gin-gonic/gin"
)
func main() {
r := gin.Default() // デフォルトでRecoveryミドルウェアを含む
r.GET("/", func(c *gin.Context) {
panic("panic error!")
})
r.Run(":8080")
}
サンプルコード
catch-panic/src/main.rs
use salvo::prelude::*;
// Handler that deliberately panics to demonstrate panic catching
#[handler]
async fn hello() {
panic!("panic error!");
}
#[tokio::main]
async fn main() {
// Initialize logging system
tracing_subscriber::fmt().init();
// Set up router with CatchPanic middleware to handle panics gracefully
// This prevents the server from crashing when a panic occurs in a handler
let router = Router::new().hoop(CatchPanic::new()).get(hello);
// Bind server to port 5800 and start serving
let acceptor = TcpListener::new("0.0.0.0:5800").bind().await;
Server::new(acceptor).serve(router).await;
}