salvo-basic-app
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseSalvo Basic Application Setup
Salvo基础应用搭建
This skill helps create basic Salvo web applications with proper structure and best practices.
本技能可帮助你遵循合理结构与最佳实践创建基础Salvo Web应用。
Core Concepts
核心概念
Handler
处理器(Handler)
Handlers process HTTP requests. Use the macro on async functions:
#[handler]rust
use salvo::prelude::*;
#[handler]
async fn hello() -> &'static str {
"Hello World"
}
#[handler]
async fn greet(req: &mut Request) -> String {
let name = req.query::<String>("name").unwrap_or("World".to_string());
format!("Hello, {}!", name)
}Handler parameters can be in any order and are all optional:
- - HTTP request object
req: &mut Request - - HTTP response object
res: &mut Response - - Request-scoped data storage
depot: &mut Depot - - Flow control for middleware
ctrl: &mut FlowCtrl
处理器用于处理HTTP请求。在异步函数上使用宏:
#[handler]rust
use salvo::prelude::*;
#[handler]
async fn hello() -> &'static str {
"Hello World"
}
#[handler]
async fn greet(req: &mut Request) -> String {
let name = req.query::<String>("name").unwrap_or("World".to_string());
format!("Hello, {}!", name)
}处理器参数可以是任意顺序,且均为可选:
- - HTTP请求对象
req: &mut Request - - HTTP响应对象
res: &mut Response - - 请求作用域的数据存储
depot: &mut Depot - - 中间件的流程控制
ctrl: &mut FlowCtrl
Router
路由(Router)
Routers define URL paths and attach handlers:
rust
use salvo::prelude::*;
let router = Router::new()
.get(hello)
.push(Router::with_path("greet").get(greet));路由用于定义URL路径并关联处理器:
rust
use salvo::prelude::*;
let router = Router::new()
.get(hello)
.push(Router::with_path("greet").get(greet));Server Setup
服务器配置
Basic server configuration:
rust
use salvo::prelude::*;
#[handler]
async fn hello() -> &'static str {
"Hello World"
}
#[tokio::main]
async fn main() {
let router = Router::new().get(hello);
let acceptor = TcpListener::new("0.0.0.0:8080").bind().await;
Server::new(acceptor).serve(router).await;
}基础服务器配置:
rust
use salvo::prelude::*;
#[handler]
async fn hello() -> &'static str {
"Hello World"
}
#[tokio::main]
async fn main() {
let router = Router::new().get(hello);
let acceptor = TcpListener::new("0.0.0.0:8080").bind().await;
Server::new(acceptor).serve(router).await;
}Response Types
响应类型
Returning Different Types
返回不同类型
Handlers can return any type implementing or :
WriterScriberust
use salvo::prelude::*;
#[handler]
async fn json_response() -> Json<serde_json::Value> {
Json(serde_json::json!({"status": "ok"}))
}
#[handler]
async fn text_response() -> &'static str {
"Plain text response"
}
#[handler]
async fn html_response(res: &mut Response) {
res.render(salvo::writing::Html("<h1>Hello</h1>"));
}
#[handler]
async fn status_response() -> StatusCode {
StatusCode::NO_CONTENT
}
#[handler]
async fn redirect_response(res: &mut Response) {
res.render(salvo::writing::Redirect::found("https://example.com"));
}处理器可以返回任何实现或的类型:
WriterScriberust
use salvo::prelude::*;
#[handler]
async fn json_response() -> Json<serde_json::Value> {
Json(serde_json::json!({"status": "ok"}))
}
#[handler]
async fn text_response() -> &'static str {
"Plain text response"
}
#[handler]
async fn html_response(res: &mut Response) {
res.render(salvo::writing::Html("<h1>Hello</h1>"));
}
#[handler]
async fn status_response() -> StatusCode {
StatusCode::NO_CONTENT
}
#[handler]
async fn redirect_response(res: &mut Response) {
res.render(salvo::writing::Redirect::found("https://example.com"));
}Rendering JSON
渲染JSON
rust
use salvo::prelude::*;
use serde::Serialize;
#[derive(Serialize)]
struct User {
name: String,
age: u8,
}
#[handler]
async fn get_user() -> Json<User> {
Json(User {
name: "Alice".to_string(),
age: 30,
})
}rust
use salvo::prelude::*;
use serde::Serialize;
#[derive(Serialize)]
struct User {
name: String,
age: u8,
}
#[handler]
async fn get_user() -> Json<User> {
Json(User {
name: "Alice".to_string(),
age: 30,
})
}Error Handling
错误处理
Return where both implement :
Result<T, E>Writerrust
use salvo::prelude::*;
#[handler]
async fn may_fail() -> Result<Json<Data>, StatusError> {
let data = fetch_data().await.map_err(|_| StatusError::internal_server_error())?;
Ok(Json(data))
}返回,其中T和E均需实现:
Result<T, E>Writerrust
use salvo::prelude::*;
#[handler]
async fn may_fail() -> Result<Json<Data>, StatusError> {
let data = fetch_data().await.map_err(|_| StatusError::internal_server_error())?;
Ok(Json(data))
}Request Object
请求对象
Common Request Methods
常用请求方法
rust
#[handler]
async fn handle_request(req: &mut Request) -> String {
// Get request method
let method = req.method();
// Get request URI
let uri = req.uri();
// Get header value
if let Some(content_type) = req.header::<String>("Content-Type") {
println!("Content-Type: {}", content_type);
}
// Get query parameter
let name = req.query::<String>("name").unwrap_or_default();
// Get path parameter (requires route like /users/{id})
let id = req.param::<i64>("id").unwrap();
// Parse JSON body
let body: UserData = req.parse_json().await.unwrap();
format!("Processed request")
}rust
#[handler]
async fn handle_request(req: &mut Request) -> String {
// 获取请求方法
let method = req.method();
// 获取请求URI
let uri = req.uri();
// 获取头信息值
if let Some(content_type) = req.header::<String>("Content-Type") {
println!("Content-Type: {}", content_type);
}
// 获取查询参数
let name = req.query::<String>("name").unwrap_or_default();
// 获取路径参数(需要类似/users/{id}的路由)
let id = req.param::<i64>("id").unwrap();
// 解析JSON请求体
let body: UserData = req.parse_json().await.unwrap();
format!("Processed request")
}Response Object
响应对象
Common Response Methods
常用响应方法
rust
use salvo::prelude::*;
#[handler]
async fn handle_response(res: &mut Response) {
// Set status code
res.status_code(StatusCode::CREATED);
// Set response header
res.headers_mut().insert("X-Custom-Header", "value".parse().unwrap());
// Render text response
res.render("Hello, World!");
}rust
use salvo::prelude::*;
#[handler]
async fn handle_response(res: &mut Response) {
// 设置状态码
res.status_code(StatusCode::CREATED);
// 设置响应头
res.headers_mut().insert("X-Custom-Header", "value".parse().unwrap());
// 渲染文本响应
res.render("Hello, World!");
}Dependencies
依赖项
Add to :
Cargo.tomltoml
[dependencies]
salvo = "0.89.0"
tokio = { version = "1", features = ["macros", "rt-multi-thread"] }
serde = { version = "1", features = ["derive"] }
serde_json = "1"添加到:
Cargo.tomltoml
[dependencies]
salvo = "0.89.0"
tokio = { version = "1", features = ["macros", "rt-multi-thread"] }
serde = { version = "1", features = ["derive"] }
serde_json = "1"Best Practices
最佳实践
- Use macro for all handlers
#[handler] - Keep handlers focused on single responsibility
- Use appropriate return types (Json, Text, StatusCode)
- Handle errors with Result types
- Use for basic HTTP servers
TcpListener - Extract common logic into middleware using
hoop()
- 为所有处理器使用宏
#[handler] - 保持处理器专注于单一职责
- 使用合适的返回类型(Json、Text、StatusCode)
- 使用Result类型处理错误
- 为基础HTTP服务器使用
TcpListener - 使用将通用逻辑提取到中间件中
hoop()