一、概述
Actix-Web中间件是用于在HTTP请求处理流程中插入自定义逻辑的组件,支持日志记录、身份验证、性能监控等功能。
二、日志中间件
修改Cargo.toml,添加futures-util 这个依赖
[dependencies]
futures-util = { version = "0.3", default-features = false, features = ["std"] }
修改主代码 src/main.rs
use actix_web::{
dev::{forward_ready, Service, ServiceRequest, ServiceResponse, Transform},
Error,
};
use actix_web::{get,App, HttpServer,Responder,HttpResponse};
use futures_util::future::LocalBoxFuture;
use std::future::{ready, Ready};
use std::time::Instant;
pub struct Logger;
impl<S, B> Transform<S, ServiceRequest> for Logger
where
S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
S::Future: 'static,
B: 'static,
{
type Response = ServiceResponse<B>;
type Error = Error;
type InitError = ();
type Transform = LoggerMiddleware<S>;
type Future = Ready<Result<Self::Transform, Self::InitError>>;
fn new_transform(&self, service: S) -> Self::Future {
ready(Ok(LoggerMiddleware { service }))
}
}
pub struct LoggerMiddleware<S> {
service: S,
}
impl<S, B> Service<ServiceRequest> for LoggerMiddleware<S>
where
S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
S::Future: 'static,
B: 'static,
{
type Response = ServiceResponse<B>;
type Error = Error;
type Future = LocalBoxFuture<'static, Result<Self::Response, Self::Error>>;
forward_ready!(service);
fn call(&self, req: ServiceRequest) -> Self::Future {
let start = Instant::now();
let method = req.method().to_string();
let path = req.path().to_string();
let fut = self.service.call(req);
Box::pin(async move {
let res = fut.await?;
let elapsed = start.elapsed();
println!(
"📊 {} {} - {} - {:?}",
method,
path,
res.status(),
elapsed
);
Ok(res)
})
}
}
#[get("/")]
async fn hello() -> impl Responder {
HttpResponse::Ok().body("Hello, Actix-Web!")
}
// 使用中间件
#[actix_web::main]
async fn main() -> std::io::Result<()> {
env_logger::init_from_env(env_logger::Env::default().default_filter_or("info"));
log::info!("Starting HTTP server on http://127.0.0.1:8080");
HttpServer::new(|| {
App::new()
.wrap(Logger) // 应用日志中间件
.service(hello)
})
.bind(("127.0.0.1", 8080))?
.run()
.await
}
重新运行,访问:http://127.0.0.1:8080/
页面显示:Hello, Actix-Web!
控制台输出
📊 GET / - 200 OK - 21.7µs
📊 GET /favicon.ico - 404 Not Found - 15.6µs
这里可以看到,已经执行了Box::pin里面的代码。
三、认证中间件
针对请求头Authorization做token验证
修改主代码 src/main.rs
use actix_web::{
dev::{Service, ServiceRequest, ServiceResponse, Transform},
error::ErrorUnauthorized,
get, App, Error, HttpResponse, HttpServer, Responder,
};
use futures_util::future::LocalBoxFuture;
use std::future::{ready, Ready};
pub struct AuthMiddleware;
impl<S, B> Transform<S, ServiceRequest> for AuthMiddleware
where
S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
S::Future: 'static,
B: 'static,
{
type Response = ServiceResponse<B>;
type Error = Error;
type InitError = ();
type Transform = AuthMiddlewareService<S>;
type Future = Ready<Result<Self::Transform, Self::InitError>>;
fn new_transform(&self, service: S) -> Self::Future {
ready(Ok(AuthMiddlewareService { service }))
}
}
pub struct AuthMiddlewareService<S> {
service: S,
}
impl<S, B> Service<ServiceRequest> for AuthMiddlewareService<S>
where
S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
S::Future: 'static,
B: 'static,
{
type Response = ServiceResponse<B>;
type Error = Error;
type Future = LocalBoxFuture<'static, Result<Self::Response, Self::Error>>;
actix_web::dev::forward_ready!(service);
fn call(&self, req: ServiceRequest) -> Self::Future {
let auth_header = req.headers().get("Authorization");
if let Some(auth) = auth_header {
if let Ok(auth_str) = auth.to_str() {
if auth_str.starts_with("Bearer ") {
let token = &auth_str[7..];
if token == "valid-token" {
let fut = self.service.call(req);
return Box::pin(async move {
fut.await
});
}
}
}
}
Box::pin(async move {
Err(ErrorUnauthorized("Invalid or missing token"))
})
}
}
#[get("/")]
async fn hello() -> impl Responder {
HttpResponse::Ok().body("Hello, Actix-Web!")
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
env_logger::init_from_env(env_logger::Env::default().default_filter_or("info"));
log::info!("Starting HTTP server on http://127.0.0.1:8080");
HttpServer::new(|| {
App::new()
.wrap(AuthMiddleware) // ✅ 应用中间件
.service(hello)
})
.bind(("127.0.0.1", 8080))?
.run()
.await
}
重新运行,访问:http://127.0.0.1:8080/
页面显示:Invalid or missing token
说明,token认证不成功,被中间件拦截了。
使用postman,携带正确的token,就可以正常访问了。

四、CORS 配置
Actix-Web 提供了内置的 CORS(跨域资源共享)支持,可以轻松配置跨域请求处理。
核心配置要点:
- 基础配置:使用
actix_cors::Cors中间件,通过default()方法创建默认配置 - 允许的来源:使用
allowed_origin()指定允许的域名,支持精确匹配和通配符 - 允许的方法:通过
allowed_methods()设置允许的 HTTP 方法(GET、POST 等) - 允许的头部:使用
allowed_headers()配置允许的请求头 - 凭据支持:通过
supports_credentials()启用 Cookie 等凭据传输
修改主代码 src/main.rs
use actix_cors::Cors;
use actix_web::{get,http, App, HttpServer,Responder,HttpResponse};
#[get("/")]
async fn hello() -> impl Responder {
HttpResponse::Ok().body("Hello, Actix-Web!")
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
env_logger::init_from_env(env_logger::Env::default().default_filter_or("info"));
log::info!("Starting HTTP server on http://127.0.0.1:8080");
HttpServer::new(|| {
let cors = Cors::default()
.allowed_origin("http://localhost:3000")
.allowed_methods(vec!["GET", "POST", "PUT", "DELETE"])
.allowed_headers(vec![http::header::AUTHORIZATION, http::header::CONTENT_TYPE])
.max_age(3600);
App::new()
.wrap(cors)
.service(hello)
})
.bind(("127.0.0.1", 8080))?
.run()
.await
}
重新运行,访问:http://127.0.0.1:8080/
页面显示:Hello, Actix-Web!
本文参考链接:https://blog.youkuaiyun.com/sinat_41617212/article/details/154069236
108

被折叠的 条评论
为什么被折叠?



