内置中间件 #
Logger 中间件 #
基本用法 #
rust
use actix_web::{middleware, App, HttpServer};
#[actix_web::main]
async fn main() -> std::io::Result<()> {
HttpServer::new(|| {
App::new()
.wrap(middleware::Logger::default())
})
.bind("127.0.0.1:8080")?
.run()
.await
}
自定义日志格式 #
rust
App::new()
.wrap(middleware::Logger::new("%a %{User-Agent}i"))
日志格式说明 #
| 占位符 | 说明 |
|---|---|
%a |
客户端 IP 地址 |
%t |
请求时间 |
%r |
请求行 |
%s |
响应状态码 |
%b |
响应大小 |
%D |
请求处理时间(毫秒) |
%T |
请求处理时间(秒) |
%{name}i |
请求头 |
%{name}o |
响应头 |
完整示例 #
rust
use actix_web::{middleware, web, App, HttpResponse, HttpServer, Responder};
async fn index() -> impl Responder {
HttpResponse::Ok().body("Hello")
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
std::env::set_var("RUST_LOG", "actix_web=info");
env_logger::init();
HttpServer::new(|| {
App::new()
.wrap(middleware::Logger::new(
"%a \"%r\" %s %b \"%{Referer}i\" \"%{User-Agent}i\" %Dms"
))
.route("/", web::get().to(index))
})
.bind("127.0.0.1:8080")?
.run()
.await
}
Compress 中间件 #
基本用法 #
rust
use actix_web::middleware::Compress;
App::new()
.wrap(Compress::default())
指定压缩级别 #
rust
App::new()
.wrap(Compress::new(actix_web::http::header::ContentEncoding::Gzip))
支持的压缩算法 #
| 算法 | 说明 |
|---|---|
| Gzip | 最常用的压缩算法 |
| Deflate | 老式压缩算法 |
| Brotli | 高压缩率算法 |
ErrorHandlers 中间件 #
基本用法 #
rust
use actix_web::{middleware, http::StatusCode, HttpResponse};
fn error_handler<B>(res: ServiceResponse<B>) -> Result<ErrorHandlerResponse<B>, Error> {
// 自定义错误处理
Ok(ErrorHandlerResponse::Response(res.map_into_left_body()))
}
App::new()
.wrap(middleware::ErrorHandlers::new()
.handler(StatusCode::NOT_FOUND, not_found_handler)
.handler(StatusCode::INTERNAL_SERVER_ERROR, error_handler)
)
自定义错误页面 #
rust
use actix_web::{
body::EitherBody,
dev::{ServiceResponse, ServiceRequest},
http::StatusCode,
middleware::{ErrorHandlerResponse, ErrorHandlers},
web, App, HttpResponse, HttpServer, Responder,
};
fn render_404<B>(res: ServiceResponse<B>) -> actix_web::Result<ErrorHandlerResponse<B>> {
let response = HttpResponse::build(StatusCode::NOT_FOUND)
.content_type("text/html")
.body("<h1>404 - Page Not Found</h1>");
let res = ServiceResponse::new(res.request().clone(), response)
.map_into_right_body();
Ok(ErrorHandlerResponse::Response(res))
}
fn render_500<B>(res: ServiceResponse<B>) -> actix_web::Result<ErrorHandlerResponse<B>> {
let response = HttpResponse::build(StatusCode::INTERNAL_SERVER_ERROR)
.content_type("text/html")
.body("<h1>500 - Internal Server Error</h1>");
let res = ServiceResponse::new(res.request().clone(), response)
.map_into_right_body();
Ok(ErrorHandlerResponse::Response(res))
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
HttpServer::new(|| {
App::new()
.wrap(ErrorHandlers::new()
.handler(StatusCode::NOT_FOUND, render_404)
.handler(StatusCode::INTERNAL_SERVER_ERROR, render_500)
)
})
.bind("127.0.0.1:8080")?
.run()
.await
}
DefaultHeaders 中间件 #
基本用法 #
rust
use actix_web::middleware::DefaultHeaders;
App::new()
.wrap(DefaultHeaders::new()
.add(("X-Version", "1.0"))
.add(("X-Frame-Options", "DENY"))
)
安全头部 #
rust
App::new()
.wrap(DefaultHeaders::new()
.add(("X-Content-Type-Options", "nosniff"))
.add(("X-Frame-Options", "SAMEORIGIN"))
.add(("X-XSS-Protection", "1; mode=block"))
.add(("Strict-Transport-Security", "max-age=31536000; includeSubDomains"))
)
Condition 中间件 #
条件启用中间件 #
rust
use actix_web::middleware::Condition;
App::new()
.wrap(Condition::new(cfg.debug, middleware::Logger::default()))
环境相关中间件 #
rust
use std::env;
#[actix_web::main]
async fn main() -> std::io::Result<()> {
let is_dev = env::var("ENV").unwrap_or_default() == "development";
HttpServer::new(move || {
App::new()
.wrap(Condition::new(is_dev, middleware::Logger::default()))
})
.bind("127.0.0.1:8080")?
.run()
.await
}
CORS 中间件 #
添加依赖 #
toml
[dependencies]
actix-cors = "0.6"
基本用法 #
rust
use actix_cors::Cors;
App::new()
.wrap(Cors::permissive())
自定义 CORS 配置 #
rust
use actix_cors::Cors;
use actix_web::http::header;
App::new()
.wrap(
Cors::default()
.allowed_origin("https://example.com")
.allowed_origin_fn(|origin, _req| {
origin.as_bytes().ends_with(b".example.com")
})
.allowed_methods(vec!["GET", "POST"])
.allowed_headers(vec![header::AUTHORIZATION, header::ACCEPT])
.allowed_header(header::CONTENT_TYPE)
.max_age(3600)
)
Identity 中间件 #
添加依赖 #
toml
[dependencies]
actix-identity = "0.6"
actix-session = "0.8"
基本配置 #
rust
use actix_identity::IdentityMiddleware;
use actix_session::{config::PersistentSession, storage::CookieSessionStore, SessionMiddleware};
use actix_web::cookie::Key;
#[actix_web::main]
async fn main() -> std::io::Result<()> {
let secret_key = Key::generate();
HttpServer::new(move || {
App::new()
.wrap(IdentityMiddleware::default())
.wrap(
SessionMiddleware::builder(CookieSessionStore::default(), secret_key.clone())
.build()
)
})
.bind("127.0.0.1:8080")?
.run()
.await
}
完整示例 #
rust
use actix_cors::Cors;
use actix_web::{
body::EitherBody,
dev::{ServiceResponse, ServiceRequest},
http::StatusCode,
middleware::{DefaultHeaders, ErrorHandlerResponse, ErrorHandlers, Logger},
web, App, HttpResponse, HttpServer, Responder,
};
async fn index() -> impl Responder {
HttpResponse::Ok().json(serde_json::json!({
"message": "Hello, World!"
}))
}
fn render_404<B>(res: ServiceResponse<B>) -> actix_web::Result<ErrorHandlerResponse<B>> {
let response = HttpResponse::build(StatusCode::NOT_FOUND)
.json(serde_json::json!({
"error": "Not Found",
"message": "The requested resource was not found"
}));
let res = ServiceResponse::new(res.request().clone(), response)
.map_into_right_body();
Ok(ErrorHandlerResponse::Response(res))
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
std::env::set_var("RUST_LOG", "info");
env_logger::init();
HttpServer::new(|| {
App::new()
.wrap(Logger::default())
.wrap(
Cors::default()
.allowed_origin("http://localhost:3000")
.allowed_methods(vec!["GET", "POST", "PUT", "DELETE"])
.allowed_header(actix_web::http::header::CONTENT_TYPE)
.max_age(3600)
)
.wrap(
DefaultHeaders::new()
.add(("X-Content-Type-Options", "nosniff"))
.add(("X-Frame-Options", "DENY"))
)
.wrap(
ErrorHandlers::new()
.handler(StatusCode::NOT_FOUND, render_404)
)
.route("/", web::get().to(index))
})
.bind("127.0.0.1:8080")?
.run()
.await
}
下一步 #
现在你已经掌握了内置中间件,继续学习 自定义中间件,了解如何编写自己的中间件!
最后更新:2026-03-29