Abfangen von Panics in Anfragen

Catch Panic dient dazu, Abstürze abzufangen, die während der Anfrageverarbeitung im Programm auftreten. Für spezifische APIs konsultieren Sie bitte die Dokumentation.

Hinweis: Um CatchPanic zu verwenden, müssen Sie das Feature catch-panic in Cargo.toml aktivieren:

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

Middleware-Einführung

CatchPanic ist eine Middleware, die entwickelt wurde, um Panics in Handlern abzufangen. Wenn während der Anfrageverarbeitung ein Panic auftritt, fängt es diesen ab und schreibt einen 500 Internal Server Error in die Antwort, wodurch verhindert wird, dass der gesamte Server abstürzt.

Wichtiger Hinweis: Diese Middleware sollte als erste Middleware verwendet werden, um sicherzustellen, dass sie Panics von anderen Middlewares oder Handlern abfangen kann.

Grundlegende Verwendung

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:8698").bind().await;
    Server::new(acceptor).serve(router).await;
}

Vergleich mit anderen Frameworks zum schnellen Konzeptverständnis

Axum

Ähnlich der catch_panic-Middleware in Axums Tower:

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)

Im Go-Framework Gin ähnlich der Recovery-Middleware:

package main

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

func main() {
    r := gin.Default() // Enthält standardmäßig die Recovery-Middleware
    
    r.GET("/", func(c *gin.Context) {
        panic("panic error!")
    })
    
    r.Run(":8080")
}

Beispielcode

main.rs
Cargo.toml
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 8698 and start serving
    let acceptor = TcpListener::new("0.0.0.0:8698").bind().await;
    Server::new(acceptor).serve(router).await;
}