一键导入
salvo-cors
Configure Cross-Origin Resource Sharing (CORS) and security headers. Use for APIs accessed from browsers on different domains.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Configure Cross-Origin Resource Sharing (CORS) and security headers. Use for APIs accessed from browsers on different domains.
用 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.
Create basic Salvo web applications with handlers, routers, and server setup. Use when starting a new Salvo project or adding basic HTTP endpoints.
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.
Implement CSRF (Cross-Site Request Forgery) protection using cookie or session storage. Use for protecting forms and state-changing endpoints.
| name | salvo-cors |
| description | Configure Cross-Origin Resource Sharing (CORS) and security headers. Use for APIs accessed from browsers on different domains. |
| version | 0.94.0 |
| tags | ["security","cors","cross-origin","headers"] |
[dependencies]
salvo = { version = "0.94.0", features = ["cors"] }
Cors is a builder; terminate with .into_handler() to get a CorsHandler you can hoop onto a router.
use salvo::cors::Cors;
use salvo::http::Method;
use salvo::prelude::*;
#[tokio::main]
async fn main() {
let cors = Cors::new()
.allow_origin("https://example.com")
.allow_methods(vec![Method::GET, Method::POST, Method::PUT, Method::DELETE])
.allow_headers(vec!["content-type", "authorization"])
.into_handler();
let router = Router::new()
.hoop(cors)
.push(Router::with_path("api").get(api_handler));
let acceptor = TcpListener::new("0.0.0.0:8080").bind().await;
Server::new(acceptor).serve(router).await;
}
#[handler]
async fn api_handler() -> &'static str { "Hello from API" }
use salvo::cors::{Any, Cors};
// Any origin, methods, headers, exposed headers. Does not allow credentials.
let cors = Cors::permissive().into_handler();
// Mirror-request variant that ALSO allows credentials. Prints a warning.
// Only safe for tightly-controlled deployments.
let cors = Cors::very_permissive().into_handler();
// Manual wildcard
let cors = Cors::new()
.allow_origin(Any)
.allow_methods(Any)
.allow_headers(Any)
.into_handler();
use salvo::cors::Cors;
use salvo::http::Method;
let cors = Cors::new()
.allow_origin(["https://app.example.com", "https://admin.example.com"])
.allow_methods(vec![Method::GET, Method::POST, Method::PUT, Method::DELETE])
.allow_headers(vec!["authorization", "content-type", "x-requested-with"])
.expose_headers(vec!["x-request-id"])
.allow_credentials(true)
.max_age(3600) // seconds, or pass a Duration
.into_handler();
Use AllowOrigin::dynamic — the closure signature is Fn(Option<&HeaderValue>, &Request, &Depot) -> Option<HeaderValue>. Return Some(origin) to accept, None to reject.
use salvo::cors::{AllowOrigin, Cors};
use salvo::http::HeaderValue;
let cors = Cors::new()
.allow_origin(AllowOrigin::dynamic(|origin, _req, _depot| {
let o = origin?.to_str().ok()?;
if o.ends_with(".example.com") || o == "https://example.com" {
HeaderValue::from_str(o).ok()
} else {
None
}
}))
.allow_methods(vec!["GET", "POST"])
.allow_credentials(true)
.into_handler();
AllowOrigin::mirror_request() reflects any origin header back (credentials-safe alternative to *).
let cors = Cors::new()
.allow_origin("https://app.example.com")
.allow_methods(vec!["GET", "POST"])
.into_handler();
let router = Router::new()
.push(
Router::with_path("api")
.hoop(cors)
.push(Router::with_path("users").get(list_users))
.push(Router::with_path("posts").get(list_posts)),
)
.push(Router::with_path("health").get(health_check));
salvo-cors only handles CORS. Add other security headers with a small custom handler:
use salvo::prelude::*;
#[handler]
async fn security_headers(res: &mut Response) {
let h = res.headers_mut();
h.insert("content-security-policy", "default-src 'self'".parse().unwrap());
h.insert("strict-transport-security", "max-age=31536000; includeSubDomains".parse().unwrap());
h.insert("x-frame-options", "DENY".parse().unwrap());
h.insert("x-content-type-options", "nosniff".parse().unwrap());
h.insert("referrer-policy", "strict-origin-when-cross-origin".parse().unwrap());
}
| Method | Description |
|---|---|
allow_origin(impl Into<AllowOrigin>) | Exact string, list, Any, or AllowOrigin::dynamic/dynamic_async/mirror_request |
allow_methods(impl Into<AllowMethods>) | Vec of Method or str, or Any |
allow_headers(impl Into<AllowHeaders>) | Vec of header names, Any, or AllowHeaders::mirror_request() |
expose_headers(...) | Response headers readable by the browser |
allow_credentials(bool) | Include cookies / auth headers |
max_age(u64 or Duration) | Cache preflight response |
allow_private_network(bool) | Opt into private network access preflights |
vary(...) | Extra Vary headers |
into_handler() | Build the CorsHandler (required) |
Cors is a builder; forgetting .into_handler() will not compile when passed to .hoop().allow_credentials(true) with any wildcard (Any on origin/methods/headers/expose_headers) panics at into_handler() time. Use an explicit list or mirror_request() instead.Access-Control-Allow-Credentials: true rather than returning an unsafe wildcard-plus-credentials response.Cors::very_permissive() intentionally logs a warning on construction — do not ship it.allow_headers are case-insensitive, but lowercase is conventional.