错误处理 #
良好的错误处理是高质量应用的重要标志。本节将介绍Rocket中的错误处理机制。
错误捕获器 #
基本捕获器 #
rust
use rocket::Request;
use rocket::response::content::RawHtml;
#[catch(404)]
fn not_found(_req: &Request) -> RawHtml<&'static str> {
RawHtml("<h1>404 - Page Not Found</h1>")
}
#[catch(500)]
fn internal_error(_req: &Request) -> RawHtml<&'static str> {
RawHtml("<h1>500 - Internal Server Error</h1>")
}
#[launch]
fn rocket() -> _ {
rocket::build()
.register("/", catchers![not_found, internal_error])
}
动态错误页面 #
rust
use rocket::Request;
use rocket_dyn_templates::Template;
use rocket::serde::Serialize;
#[derive(Serialize)]
struct ErrorContext {
code: u16,
message: String,
path: String,
}
#[catch(404)]
fn not_found(req: &Request) -> Template {
Template::render("error", &ErrorContext {
code: 404,
message: "Page not found".to_string(),
path: req.uri().path().to_string(),
})
}
#[catch(500)]
fn internal_error(_req: &Request) -> Template {
Template::render("error", &ErrorContext {
code: 500,
message: "Internal server error".to_string(),
path: String::new(),
})
}
自定义错误类型 #
错误枚举 #
rust
use rocket::http::Status;
use rocket::response::{Responder, Result};
use rocket::serde::json::Json;
use rocket::serde::Serialize;
use std::fmt;
#[derive(Debug)]
pub enum ApiError {
NotFound(String),
Unauthorized,
BadRequest(String),
InternalError(String),
}
impl fmt::Display for ApiError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
ApiError::NotFound(msg) => write!(f, "Not Found: {}", msg),
ApiError::Unauthorized => write!(f, "Unauthorized"),
ApiError::BadRequest(msg) => write!(f, "Bad Request: {}", msg),
ApiError::InternalError(msg) => write!(f, "Internal Error: {}", msg),
}
}
}
#[derive(Serialize)]
struct ErrorResponse {
error: String,
code: u16,
}
impl<'r> Responder<'r, 'r> for ApiError {
fn respond_to(self, _req: &'r rocket::Request<'_>) -> Result<'r> {
let (status, message) = match self {
ApiError::NotFound(msg) => (Status::NotFound, msg),
ApiError::Unauthorized => (Status::Unauthorized, "Unauthorized".to_string()),
ApiError::BadRequest(msg) => (Status::BadRequest, msg),
ApiError::InternalError(msg) => (Status::InternalServerError, msg),
};
let body = Json(ErrorResponse {
error: message,
code: status.code,
});
rocket::response::Response::build_from(body.respond_to(_req)?)
.status(status)
.ok()
}
}
使用自定义错误 #
rust
#[get("/users/<id>")]
async fn get_user(id: i32, db: &State<Db>) -> Result<Json<User>, ApiError> {
db.find_user(id)
.await
.map(Json)
.ok_or_else(|| ApiError::NotFound(format!("User {} not found", id)))
}
Result类型处理 #
Option到Result转换 #
rust
use rocket::http::Status;
#[get("/items/<id>")]
fn get_item(id: u32) -> Result<Json<Item>, Status> {
find_item(id)
.map(Json)
.ok_or(Status::NotFound)
}
链式错误处理 #
rust
#[get("/users/<user_id>/posts/<post_id>")]
async fn get_user_post(
user_id: u32,
post_id: u32,
db: &State<Db>,
) -> Result<Json<Post>, ApiError> {
let user = db.find_user(user_id)
.await
.ok_or_else(|| ApiError::NotFound(format!("User {} not found", user_id)))?;
let post = db.find_post(post_id)
.await
.ok_or_else(|| ApiError::NotFound(format!("Post {} not found", post_id)))?;
if post.user_id != user.id {
return Err(ApiError::Unauthorized);
}
Ok(Json(post))
}
表单验证错误 #
rust
use rocket::form::{self, Form, Contextual};
#[derive(FromForm)]
struct UserForm {
#[field(validate = len(3..=20))]
username: String,
#[field(validate = len(8..))]
password: String,
}
#[post("/register", data = "<form>")]
fn register(form: Result<Form<UserForm>, form::Error<'_>>) -> Result<Redirect, String> {
let form = form.map_err(|e| format!("Form error: {}", e))?;
Ok(Redirect::to("/success"))
}
完整示例 #
rust
#[macro_use] extern crate rocket;
use rocket::http::Status;
use rocket::response::{Responder, Result};
use rocket::serde::json::Json;
use rocket::serde::Serialize;
use rocket::response::content::RawHtml;
#[derive(Debug)]
enum ApiError {
NotFound(String),
BadRequest(String),
Internal(String),
}
#[derive(Serialize)]
struct ErrorResponse {
error: String,
code: u16,
}
impl<'r> Responder<'r, 'r> for ApiError {
fn respond_to(self, _req: &'r rocket::Request<'_>) -> Result<'r> {
let (status, message) = match self {
ApiError::NotFound(m) => (Status::NotFound, m),
ApiError::BadRequest(m) => (Status::BadRequest, m),
ApiError::Internal(m) => (Status::InternalServerError, m),
};
rocket::response::Response::build()
.status(status)
.header(rocket::http::ContentType::JSON)
.sized_body(
serde_json::to_string(&ErrorResponse {
error: message,
code: status.code,
}).unwrap().len(),
std::io::Cursor::new(
serde_json::to_string(&ErrorResponse {
error: String::new(),
code: status.code,
}).unwrap()
)
)
.ok()
}
}
#[catch(404)]
fn not_found() -> RawHtml<&'static str> {
RawHtml("<h1>404 - Not Found</h1>")
}
#[catch(500)]
fn server_error() -> RawHtml<&'static str> {
RawHtml("<h1>500 - Server Error</h1>")
}
#[get("/")]
fn index() -> &'static str {
"API Running"
}
#[get("/user/<id>")]
fn get_user(id: u32) -> Result<Json<serde_json::Value>, ApiError> {
if id == 0 {
Err(ApiError::NotFound("User not found".to_string()))
} else if id > 1000 {
Err(ApiError::BadRequest("Invalid user ID".to_string()))
} else {
Ok(Json(serde_json::json!({ "id": id, "name": "User" })))
}
}
#[launch]
fn rocket() -> _ {
rocket::build()
.register("/", catchers![not_found, server_error])
.mount("/api", routes![index, get_user])
}
下一步 #
掌握了错误处理后,让我们继续学习 配置管理,了解Rocket的配置系统。
最后更新:2026-03-28