响应类型 #
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