Actix-Web中间件开发
一、概述
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.csdn.net/sinat_41617212/article/details/154069236

浙公网安备 33010602011771号