Catturare i Panic nelle Richieste

Catch Panic viene utilizzato per catturare i crash che si verificano durante l'elaborazione delle richieste da parte del programma. Per i dettagli sulle API, consultare la documentazione.

Nota: Per utilizzare CatchPanic, è necessario abilitare la feature catch-panic in Cargo.toml:

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

Introduzione al Middleware

CatchPanic è un middleware progettato per catturare i panic nei gestori. Quando si verifica un panic durante l'elaborazione di una richiesta, questo middleware lo intercetta e restituisce una risposta 500 Internal Server Error, evitando che l'intero server si arresti.

Importante: Questo middleware dovrebbe essere utilizzato come primo middleware per garantire che possa catturare i panic provenienti da altri middleware o gestori.

Utilizzo Base

use salvo_core::prelude::*;
use salvo_extra::catch_panic::CatchPanic;

#[handler]
async fn hello() {
    panic!("errore di panic!");
}

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

Confronto con Altri Framework per una Comprensione Rapida dei Concetti

Axum

Equivalente al middleware catch_panic di Tower in Axum:

use axum::{
    Router,
    routing::get,
    http::StatusCode,
};
use tower::ServiceBuilder;
use tower_http::catch_panic::CatchPanicLayer;

async fn panic_handler() -> &'static str {
    panic!("errore di panic!");
}

#[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)

In Go, con il framework Gin, è simile al middleware Recovery:

package main

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

func main() {
    r := gin.Default() // Include già il middleware Recovery di default
    
    r.GET("/", func(c *gin.Context) {
        panic("errore di panic!")
    })
    
    r.Run(":8080")
}

Codice di Esempio

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