salvo-cors
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseSalvo CORS Configuration
Salvo CORS 配置
This skill helps configure CORS and security headers in Salvo applications.
本技能可帮助你在Salvo应用中配置CORS和安全头。
Understanding CORS
了解CORS
CORS (Cross-Origin Resource Sharing) is a browser security feature that restricts web pages from making requests to different domains. Without proper CORS configuration, browsers will block cross-origin requests to your API.
CORS(跨源资源共享)是浏览器的一种安全功能,用于限制网页向不同域发起请求。如果没有正确配置CORS,浏览器会阻止对你的API的跨源请求。
Setup
设置步骤
toml
[dependencies]
salvo = { version = "0.89.0", features = ["cors"] }toml
[dependencies]
salvo = { version = "0.89.0", features = ["cors"] }Basic CORS Configuration
基础CORS配置
rust
use salvo::cors::Cors;
use salvo::prelude::*;
#[tokio::main]
async fn main() {
let cors = Cors::new()
.allow_origin("https://example.com")
.allow_methods(vec!["GET", "POST", "PUT", "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"
}rust
use salvo::cors::Cors;
use salvo::prelude::*;
#[tokio::main]
async fn main() {
let cors = Cors::new()
.allow_origin("https://example.com")
.allow_methods(vec!["GET", "POST", "PUT", "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"
}Allow All Origins (Development)
允许所有源(开发环境)
rust
use salvo::cors::Cors;
// WARNING: Only use in development
let cors = Cors::new()
.allow_origin("*")
.allow_methods(vec!["GET", "POST", "PUT", "DELETE", "OPTIONS"])
.allow_headers(vec!["*"])
.into_handler();rust
use salvo::cors::Cors;
// 警告:仅在开发环境中使用
let cors = Cors::new()
.allow_origin("*")
.allow_methods(vec!["GET", "POST", "PUT", "DELETE", "OPTIONS"])
.allow_headers(vec!["*"])
.into_handler();Production CORS Configuration
生产环境CORS配置
rust
use salvo::cors::Cors;
use salvo::http::Method;
let cors = Cors::new()
// Specific allowed origins
.allow_origin(["https://app.example.com", "https://admin.example.com"])
// Allowed HTTP methods
.allow_methods(vec![Method::GET, Method::POST, Method::PUT, Method::DELETE])
// Allowed request headers
.allow_headers(vec!["Authorization", "Content-Type", "X-Requested-With"])
// Allow credentials (cookies, auth headers)
.allow_credentials(true)
// Cache preflight requests for 1 hour
.max_age(3600)
.into_handler();rust
use salvo::cors::Cors;
use salvo::http::Method;
let cors = Cors::new()
// 允许的特定源
.allow_origin(["https://app.example.com", "https://admin.example.com"])
// 允许的HTTP方法
.allow_methods(vec![Method::GET, Method::POST, Method::PUT, Method::DELETE])
// 允许的请求头
.allow_headers(vec!["Authorization", "Content-Type", "X-Requested-With"])
// 允许凭证(Cookie、认证头)
.allow_credentials(true)
// 预检请求缓存1小时
.max_age(3600)
.into_handler();Permissive CORS
宽松模式CORS
Use the built-in permissive preset for quick setup:
rust
use salvo::cors::Cors;
let cors = Cors::permissive();
let router = Router::new()
.hoop(cors)
.get(handler);使用内置的宽松预设快速配置:
rust
use salvo::cors::Cors;
let cors = Cors::permissive();
let router = Router::new()
.hoop(cors)
.get(handler);CORS with Specific Routes
为特定路由配置CORS
Apply CORS only to API routes:
rust
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) // CORS only for /api routes
.push(Router::with_path("users").get(list_users))
.push(Router::with_path("posts").get(list_posts))
)
.push(
Router::with_path("health")
.get(health_check) // No CORS needed
);仅对API路由应用CORS:
rust
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) // 仅对/api路由应用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) // 无需CORS
);Security Headers Middleware
安全头中间件
Add security headers to protect against common attacks:
rust
use salvo::prelude::*;
#[handler]
async fn security_headers(req: &mut Request, depot: &mut Depot, res: &mut Response, ctrl: &mut FlowCtrl) {
// Content Security Policy - prevent XSS
res.headers_mut().insert(
"Content-Security-Policy",
"default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'".parse().unwrap()
);
// HTTP Strict Transport Security - force HTTPS
res.headers_mut().insert(
"Strict-Transport-Security",
"max-age=31536000; includeSubDomains; preload".parse().unwrap()
);
// Prevent clickjacking
res.headers_mut().insert(
"X-Frame-Options",
"DENY".parse().unwrap()
);
// Prevent MIME type sniffing
res.headers_mut().insert(
"X-Content-Type-Options",
"nosniff".parse().unwrap()
);
// XSS Protection
res.headers_mut().insert(
"X-XSS-Protection",
"1; mode=block".parse().unwrap()
);
// Referrer Policy
res.headers_mut().insert(
"Referrer-Policy",
"strict-origin-when-cross-origin".parse().unwrap()
);
ctrl.call_next(req, depot, res).await;
}添加安全头以防范常见攻击:
rust
use salvo::prelude::*;
#[handler]
async fn security_headers(req: &mut Request, depot: &mut Depot, res: &mut Response, ctrl: &mut FlowCtrl) {
// 内容安全策略 - 防止XSS攻击
res.headers_mut().insert(
"Content-Security-Policy",
"default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'".parse().unwrap()
);
// HTTP严格传输安全 - 强制使用HTTPS
res.headers_mut().insert(
"Strict-Transport-Security",
"max-age=31536000; includeSubDomains; preload".parse().unwrap()
);
// 防止点击劫持
res.headers_mut().insert(
"X-Frame-Options",
"DENY".parse().unwrap()
);
// 防止MIME类型嗅探
res.headers_mut().insert(
"X-Content-Type-Options",
"nosniff".parse().unwrap()
);
// XSS保护
res.headers_mut().insert(
"X-XSS-Protection",
"1; mode=block".parse().unwrap()
);
// 引用策略
res.headers_mut().insert(
"Referrer-Policy",
"strict-origin-when-cross-origin".parse().unwrap()
);
ctrl.call_next(req, depot, res).await;
}Complete Example with CORS and Security Headers
包含CORS和安全头的完整示例
rust
use salvo::cors::Cors;
use salvo::http::Method;
use salvo::prelude::*;
#[handler]
async fn security_headers(req: &mut Request, depot: &mut Depot, res: &mut Response, ctrl: &mut FlowCtrl) {
res.headers_mut().insert("X-Content-Type-Options", "nosniff".parse().unwrap());
res.headers_mut().insert("X-Frame-Options", "DENY".parse().unwrap());
res.headers_mut().insert("X-XSS-Protection", "1; mode=block".parse().unwrap());
ctrl.call_next(req, depot, res).await;
}
#[handler]
async fn api_handler() -> Json<serde_json::Value> {
Json(serde_json::json!({"status": "ok"}))
}
#[tokio::main]
async fn main() {
// CORS configuration
let cors = Cors::new()
.allow_origin(["https://app.example.com"])
.allow_methods(vec![Method::GET, Method::POST, Method::PUT, Method::DELETE])
.allow_headers(vec!["Authorization", "Content-Type"])
.allow_credentials(true)
.max_age(86400)
.into_handler();
let router = Router::new()
.hoop(security_headers) // Apply security headers globally
.hoop(cors) // Apply CORS globally
.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;
}rust
use salvo::cors::Cors;
use salvo::http::Method;
use salvo::prelude::*;
#[handler]
async fn security_headers(req: &mut Request, depot: &mut Depot, res: &mut Response, ctrl: &mut FlowCtrl) {
res.headers_mut().insert("X-Content-Type-Options", "nosniff".parse().unwrap());
res.headers_mut().insert("X-Frame-Options", "DENY".parse().unwrap());
res.headers_mut().insert("X-XSS-Protection", "1; mode=block".parse().unwrap());
ctrl.call_next(req, depot, res).await;
}
#[handler]
async fn api_handler() -> Json<serde_json::Value> {
Json(serde_json::json!({"status": "ok"}))
}
#[tokio::main]
async fn main() {
// CORS配置
let cors = Cors::new()
.allow_origin(["https://app.example.com"])
.allow_methods(vec![Method::GET, Method::POST, Method::PUT, Method::DELETE])
.allow_headers(vec!["Authorization", "Content-Type"])
.allow_credentials(true)
.max_age(86400)
.into_handler();
let router = Router::new()
.hoop(security_headers) // 全局应用安全头
.hoop(cors) // 全局应用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;
}Dynamic CORS Origins
动态CORS源
Allow origins based on request:
rust
use salvo::cors::Cors;
use salvo::prelude::*;
fn create_cors() -> Cors {
Cors::new()
.allow_origin(|origin: &str, _req: &Request| {
// Allow any subdomain of example.com
origin.ends_with(".example.com") || origin == "https://example.com"
})
.allow_methods(vec!["GET", "POST"])
.allow_credentials(true)
}根据请求允许不同的源:
rust
use salvo::cors::Cors;
use salvo::prelude::*;
fn create_cors() -> Cors {
Cors::new()
.allow_origin(|origin: &str, _req: &Request| {
// 允许example.com的所有子域
origin.ends_with(".example.com") || origin == "https://example.com"
})
.allow_methods(vec!["GET", "POST"])
.allow_credentials(true)
}CORS Configuration Options
CORS配置选项
| Option | Description |
|---|---|
| Origins allowed to make requests |
| HTTP methods allowed |
| Request headers allowed |
| Response headers exposed to browser |
| Allow cookies and auth headers |
| Cache preflight response (seconds) |
| 选项 | 描述 |
|---|---|
| 允许发起请求的源 |
| 允许的HTTP方法 |
| 允许的请求头 |
| 暴露给浏览器的响应头 |
| 允许Cookie和认证头 |
| 预检响应缓存时间(秒) |
Troubleshooting CORS Issues
CORS问题排查
Common Problems
常见问题
- Missing OPTIONS handler: CORS preflight uses OPTIONS method
- Credentials with wildcard origin: Cannot use with
*allow_credentials(true) - Missing headers: Ensure all required headers are in
allow_headers()
- 缺失OPTIONS处理器:CORS预检请求使用OPTIONS方法
- 凭证与通配符源冲突:不能与
allow_credentials(true)源同时使用* - 缺失必要头:确保所有需要的头都在中配置
allow_headers()
Debug CORS
调试CORS
rust
#[handler]
async fn cors_debug(req: &Request) {
println!("Origin: {:?}", req.header::<String>("Origin"));
println!("Method: {}", req.method());
println!("Headers: {:?}", req.headers());
}rust
#[handler]
async fn cors_debug(req: &Request) {
println!("Origin: {:?}", req.header::<String>("Origin"));
println!("Method: {}", req.method());
println!("Headers: {:?}", req.headers());
}Best Practices
最佳实践
- Specify exact origins in production: Avoid for security
* - Limit allowed methods: Only enable methods your API uses
- Validate headers: Only allow headers you need
- Use HTTPS: Always use HTTPS in production
- Set appropriate max_age: Balance security and performance
- Apply security headers: Add CSP, HSTS, X-Frame-Options
- Test preflight requests: Verify OPTIONS requests work correctly
- 生产环境指定精确源:为了安全避免使用
* - 限制允许的方法:仅启用API实际使用的方法
- 验证请求头:仅允许需要的头
- 使用HTTPS:生产环境始终使用HTTPS
- 设置合适的max_age:平衡安全性和性能
- 添加安全头:配置CSP、HSTS、X-Frame-Options等
- 测试预检请求:验证OPTIONS请求是否正常工作