一键导入
salvo-basic-app
Create basic Salvo web applications with handlers, routers, and server setup. Use when starting a new Salvo project or adding basic HTTP endpoints.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Create basic Salvo web applications with handlers, routers, and server setup. Use when starting a new Salvo project or adding basic HTTP endpoints.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Implement authentication and authorization using JWT, Basic Auth, or custom schemes. Use for securing API endpoints and user management.
Implement caching strategies for improved performance. Use for reducing database load and speeding up responses.
Compress HTTP responses using gzip, brotli, zstd, or deflate. Use for reducing bandwidth and improving load times.
Limit concurrent requests to protect resources. Use for file uploads, expensive operations, and preventing resource exhaustion.
Configure Cross-Origin Resource Sharing (CORS) and security headers. Use for APIs accessed from browsers on different domains.
Implement CSRF (Cross-Site Request Forgery) protection using cookie or session storage. Use for protecting forms and state-changing endpoints.
| name | salvo-basic-app |
| description | Create basic Salvo web applications with handlers, routers, and server setup. Use when starting a new Salvo project or adding basic HTTP endpoints. |
| version | 0.94.0 |
| tags | ["core","getting-started","handler","router"] |
Salvo 0.94 requires Rust 1.94 or newer.
[dependencies]
salvo = "0.94.0"
tokio = { version = "1", features = ["macros", "rt-multi-thread"] }
serde = { version = "1", features = ["derive"] }
serde_json = "1"
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;
}
The #[handler] macro turns an async function into a Handler. All parameters are optional and order-independent:
req: &mut Request — HTTP requestres: &mut Response — HTTP responsedepot: &mut Depot — request-scoped storagectrl: &mut FlowCtrl — middleware flow controlA handler can return any type implementing Writer or Scribe (including (), &'static str, String, Json<T>, StatusCode, Result<T, E>), or write directly via res.render(...).
use salvo::prelude::*;
use salvo::writing::Text;
use serde::Serialize;
#[derive(Serialize)]
struct User { name: String, age: u8 }
#[handler]
async fn json_body() -> Json<User> {
Json(User { name: "Alice".into(), age: 30 })
}
#[handler]
async fn html_body() -> Text<&'static str> {
Text::Html("<h1>Hello</h1>")
}
#[handler]
async fn no_content() -> StatusCode {
StatusCode::NO_CONTENT
}
#[handler]
async fn go_elsewhere(res: &mut Response) {
res.render(Redirect::found("https://example.com"));
}
HTML rendering uses Text::Html(...) (also Text::Plain, Text::Json, Text::Xml, Text::Css). There is no salvo::writing::Html type.
Return Result<T, E> where E: Writer. StatusError is the canonical error type:
#[handler]
async fn may_fail() -> Result<Json<User>, StatusError> {
let user = fetch_user().await
.map_err(|e| StatusError::internal_server_error().cause(e))?;
Ok(Json(user))
}
Available constructors: bad_request(), unauthorized(), forbidden(), not_found(), internal_server_error(), etc. Chain .brief(...), .detail(...), .cause(...) for context.
#[handler]
async fn inspect(req: &mut Request) -> String {
let method = req.method();
let path = req.uri().path();
let ct: Option<String> = req.header("Content-Type");
let name: Option<String> = req.query("name"); // ?name=...
let id: Option<i64> = req.param("id"); // /{id}
let body: MyData = req.parse_json().await.unwrap(); // JSON body
format!("{method} {path}")
}
header, query, and param are generic over T: Deserialize and return Option<T>. parse_json returns Result.
#[handler]
async fn created(res: &mut Response) {
res.status_code(StatusCode::CREATED);
res.headers_mut().insert("X-Custom", "value".parse().unwrap());
res.render(Json(serde_json::json!({"ok": true})));
}