响应类型 #

Rocket提供了丰富的响应类型支持,可以轻松返回各种格式的HTTP响应。本节将介绍Rocket中的响应类型系统。

响应类型概述 #

Rocket处理函数可以返回任何实现了 Responder trait 的类型。

常用响应类型 #

类型 说明 Content-Type
&str / String 字符串响应 text/plain
Json<T> JSON响应 application/json
Html<T> HTML响应 text/html
File 文件响应 根据文件类型
Redirect 重定向 -
Status 状态码 -

字符串响应 #

静态字符串 #

rust
#[get("/")]
fn index() -> &'static str {
    "Hello, World!"
}

动态字符串 #

rust
#[get("/hello/<name>")]
fn hello(name: &str) -> String {
    format!("Hello, {}!", name)
}

内容类型 #

rust
use rocket::response::content::RawText;

#[get("/text")]
fn text() -> RawText<&'static str> {
    RawText("Plain text response")
}

HTML响应 #

基本HTML #

rust
use rocket::response::content::RawHtml;

#[get("/")]
fn index() -> RawHtml<&'static str> {
    RawHtml(r#"
        <!DOCTYPE html>
        <html>
            <head><title>Home</title></head>
            <body><h1>Welcome!</h1></body>
        </html>
    "#)
}

动态HTML #

rust
#[get("/user/<name>")]
fn user_page(name: &str) -> RawHtml<String> {
    RawHtml(format!(r#"
        <!DOCTYPE html>
        <html>
            <head><title>{}</title></head>
            <body><h1>Hello, {}!</h1></body>
        </html>
    "#, name, name))
}

JSON响应 #

基本JSON #

rust
use rocket::serde::json::Json;
use rocket::serde::{Serialize, Deserialize};

#[derive(Serialize, Deserialize)]
#[serde(crate = "rocket::serde")]
struct User {
    id: u32,
    name: String,
}

#[get("/user/<id>")]
fn get_user(id: u32) -> Json<User> {
    Json(User {
        id,
        name: "Alice".to_string(),
    })
}

JSON数组 #

rust
#[get("/users")]
fn list_users() -> Json<Vec<User>> {
    Json(vec![
        User { id: 1, name: "Alice".to_string() },
        User { id: 2, name: "Bob".to_string() },
    ])
}

状态码响应 #

使用Status #

rust
use rocket::http::Status;

#[get("/not-found")]
fn not_found() -> Status {
    Status::NotFound
}

常用状态码 #

状态码 常量 说明
200 Ok 成功
201 Created 已创建
204 NoContent 无内容
400 BadRequest 错误请求
401 Unauthorized 未授权
403 Forbidden 禁止访问
404 NotFound 未找到
500 InternalServerError 服务器错误

组合状态码和内容 #

rust
use rocket::response::status;

#[post("/users")]
fn create_user() -> status::Created<&'static str> {
    status::Created("User created")
}

#[get("/no-content")]
fn no_content() -> status::NoContent {
    status::NoContent
}

重定向响应 #

临时重定向 #

rust
use rocket::response::Redirect;

#[get("/old")]
fn old_url() -> Redirect {
    Redirect::to("/new")
}

永久重定向 #

rust
#[get("/permanent")]
fn permanent_redirect() -> Redirect {
    Redirect::permanent("/new-location")
}

动态重定向 #

rust
#[get("/go/<destination>")]
fn go_to(destination: &str) -> Redirect {
    Redirect::to(format!("/destination/{}", destination))
}

文件响应 #

命名文件 #

rust
use rocket::fs::NamedFile;

#[get("/download/<filename>")]
async fn download(filename: &str) -> Option<NamedFile> {
    NamedFile::open(format!("files/{}", filename)).await.ok()
}

文件下载 #

rust
use rocket::fs::NamedFile;
use rocket::http::ContentType;

#[get("/download-file")]
async fn download_file() -> Option<(ContentType, NamedFile)> {
    let file = NamedFile::open("files/document.pdf").await.ok()?;
    Some((ContentType::PDF, file))
}

自定义响应 #

实现Responder #

rust
use rocket::response::{Responder, Result};
use rocket::request::Request;
use rocket::http::{ContentType, Status};

struct CustomResponse {
    content: String,
    status: Status,
}

impl<'r> Responder<'r, 'r> for CustomResponse {
    fn respond_to(self, _request: &'r Request<'_>) -> Result<'r> {
        rocket::response::Response::build()
            .status(self.status)
            .header(ContentType::Plain)
            .sized_body(self.content.len(), std::io::Cursor::new(self.content))
            .ok()
    }
}

#[get("/custom")]
fn custom() -> CustomResponse {
    CustomResponse {
        content: "Custom response".to_string(),
        status: Status::Ok,
    }
}

带头部响应 #

rust
use rocket::http::Header;
use rocket::response::content::RawText;

#[get("/with-headers")]
fn with_headers() -> (RawText<&'static str>, Header<'static>, Header<'static>) {
    (
        RawText("Response with headers"),
        Header::new("X-Custom-Header", "value"),
        Header::new("X-Another-Header", "another"),
    )
}

Result类型响应 #

使用Result #

rust
use rocket::http::Status;

#[get("/user/<id>")]
fn get_user(id: u32) -> Result<Json<User>, Status> {
    if id == 0 {
        Err(Status::NotFound)
    } else {
        Ok(Json(User {
            id,
            name: "Alice".to_string(),
        }))
    }
}

自定义错误类型 #

rust
use rocket::response::{Responder, Result};
use rocket::http::Status;
use rocket::serde::json::Json;

#[derive(Debug)]
enum ApiError {
    NotFound,
    Unauthorized,
    InternalError,
}

impl<'r> Responder<'r, 'r> for ApiError {
    fn respond_to(self, _request: &'r Request<'_>) -> Result<'r> {
        let status = match self {
            ApiError::NotFound => Status::NotFound,
            ApiError::Unauthorized => Status::Unauthorized,
            ApiError::InternalError => Status::InternalServerError,
        };
        Err(status)
    }
}

#[get("/item/<id>")]
fn get_item(id: u32) -> Result<Json<Item>, ApiError> {
    if id == 0 {
        Err(ApiError::NotFound)
    } else {
        Ok(Json(Item { id, name: "Item".to_string() }))
    }
}

流式响应 #

流式数据 #

rust
use rocket::response::stream::{Event, EventStream};
use rocket::tokio::stream::StreamExt;

#[get("/events")]
async fn events() -> EventStream![] {
    EventStream! {
        let mut count = 0u64;
        loop {
            yield Event::data(&format!("Count: {}", count));
            count += 1;
            rocket::tokio::time::sleep(std::time::Duration::from_secs(1)).await;
        }
    }
}

完整示例 #

rust
#[macro_use] extern crate rocket;

use rocket::serde::json::Json;
use rocket::serde::{Serialize, Deserialize};
use rocket::response::{Redirect, content::RawHtml};
use rocket::http::Status;
use rocket::response::status;

#[derive(Serialize, Deserialize)]
#[serde(crate = "rocket::serde")]
struct User {
    id: u32,
    name: String,
    email: String,
}

#[derive(Serialize)]
#[serde(crate = "rocket::serde")]
struct ErrorResponse {
    error: String,
    code: u16,
}

#[get("/")]
fn index() -> RawHtml<&'static str> {
    RawHtml(r#"
        <h1>API Demo</h1>
        <ul>
            <li><a href="/html">HTML Response</a></li>
            <li><a href="/json">JSON Response</a></li>
            <li><a href="/redirect">Redirect</a></li>
            <li><a href="/status">Status Code</a></li>
        </ul>
    "#)
}

#[get("/html")]
fn html_response() -> RawHtml<&'static str> {
    RawHtml("<h1>HTML Response</h1><p>This is an HTML response.</p>")
}

#[get("/json")]
fn json_response() -> Json<User> {
    Json(User {
        id: 1,
        name: "Alice".to_string(),
        email: "alice@example.com".to_string(),
    })
}

#[get("/user/<id>")]
fn get_user(id: u32) -> Result<Json<User>, (Status, Json<ErrorResponse>)> {
    if id == 0 {
        Err((
            Status::NotFound,
            Json(ErrorResponse {
                error: "User not found".to_string(),
                code: 404,
            }),
        ))
    } else {
        Ok(Json(User {
            id,
            name: format!("User {}", id),
            email: format!("user{}@example.com", id),
        }))
    }
}

#[get("/redirect")]
fn redirect_example() -> Redirect {
    Redirect::to("/html")
}

#[get("/status")]
fn status_example() -> status::NoContent {
    status::NoContent
}

#[post("/created")]
fn created_example() -> status::Created<Json<User>> {
    status::Created(Json(User {
        id: 1,
        name: "New User".to_string(),
        email: "new@example.com".to_string(),
    }))
}

#[launch]
fn rocket() -> _ {
    rocket::build()
        .mount("/", routes![
            index,
            html_response,
            json_response,
            get_user,
            redirect_example,
            status_example,
            created_example
        ])
}

下一步 #

掌握了响应类型后,让我们继续学习 JSON响应,深入了解JSON API的设计模式。

最后更新:2026-03-28