Capturer les Panics dans les Requêtes

Le middleware Catch Panic permet d'intercepter les plantages qui surviennent lors du traitement des requêtes par l'application. Pour les détails de l'API, veuillez consulter la documentation.

Note: Pour utiliser CatchPanic, vous devez activer la fonctionnalité catch-panic dans Cargo.toml:

salvo= { version = "xxx", features = ["catch-panic"] }

Présentation du Middleware

CatchPanic est un middleware qui capture les panics dans les handlers. Lorsqu'un panic survient pendant le traitement d'une requête, il l'intercepte et renvoie une réponse 500 Internal Server Error au lieu de faire crasher tout le serveur.

Important: Ce middleware doit être utilisé en premier pour garantir qu'il capture bien les panics provenant des autres middlewares ou handlers.

Utilisation Basique

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;
}

Comparaison avec d'autres Frameworks pour une Compréhension Rapide

Axum

Équivalent du middleware catch_panic de Tower dans Axum:

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)

Dans le framework Gin en Go, l'équivalent est le middleware Recovery:

package main

import (
    "github.com/gin-gonic/gin"
)

func main() {
    r := gin.Default() // Inclut par défaut le middleware Recovery
    
    r.GET("/", func(c *gin.Context) {
        panic("panic error!")
    })
    
    r.Run(":8080")
}

Exemple de Code

main.rs
Cargo.toml
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;
}