rust中間件actix_web在項目中的使用實戰(zhàn)
actix_web 中間件
- 自定義中間件
- 日志中間件
- Default headers
- 用戶會話
- 錯誤處理
中間件
中間件介紹 Actix Web 的中間件系統(tǒng)允許我們在請求/響應(yīng)處理中添加額外的行為。中間件可以與傳入的請求進程掛鉤,使我們能夠秀姑請求以及暫停請求處理以提前返回響應(yīng)。
中間件可以hook到響應(yīng)處理,通常中間件涉及一下操作
- 預(yù)處理請求
- 后處理請求
- 修改應(yīng)用狀態(tài)
- 訪問外部服務(wù)(redis、日志、會話)
中間件為每個應(yīng)用程序、范圍或資源注冊,并以與注冊相反的順序執(zhí)行。一般來說,中間件是一種實現(xiàn) Service 特征和 Transform 特征的類型。每個方法都有一個默認實現(xiàn),每個方法都可以立即返回結(jié)果或返回未來的對象。
自定義中間件
use std::future::{ready, Ready}; use actix_web::{ dev::{forward_ready, Service, ServiceRequest, ServiceResponse, Transform}, Error, }; use futures_util::future::LocalBoxFuture; // There are two steps in middleware processing. // 1. Middleware initialization, middleware factory gets called with // next service in chain as parameter. // 2. Middleware's call method gets called with normal request. pub struct SayHi; // Middleware factory is `Transform` trait // `S` - type of the next service // `B` - type of response's body impl<S, B> Transform<S, ServiceRequest> for SayHi 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 = SayHiMiddleware<S>; type Future = Ready<Result<Self::Transform, Self::InitError>>; fn new_transform(&self, service: S) -> Self::Future { ready(Ok(SayHiMiddleware { service })) } } pub struct SayHiMiddleware<S> { service: S, } impl<S, B> Service<ServiceRequest> for SayHiMiddleware<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 { println!("Hi from start. You requested: {}", req.path()); let fut = self.service.call(req); Box::pin(async move { let res = fut.await?; println!("Hi from response"); Ok(res) }) } }
對于簡單的用例,可以使用 wrap_fn 來創(chuàng)建笑的,特別的中間件。
use actix_web::{dev::Service as _, web, App}; use futures_util::future::FutureExt; #[actix_web::main] async fn main() { let app = App::new() .wrap_fn(|req, srv| { println!("Hi from start. You requested: {}", req.path()); srv.call(req).map(|res| { println!("Hi from response"); res }) }) .route( "/index.html", web::get().to(|| async { "Hello, middleware!" }), ); }
日志中間件
日志是作為中間件實現(xiàn)的,通常將日志中間件注冊為應(yīng)用程序的第一個中間件,必須為每個應(yīng)用程序注冊日志中間件。
Logger 中間件使用標準日志箱記錄信息,您應(yīng)該為actix web 包啟用記錄器以表查看訪問日志(env_logger或類似)。
使用指定的格式創(chuàng)建 Logger 中間件。默認記錄器可以用默認方法創(chuàng)建,使用默認的格式。
%a %t "%r" %s %b "%{Referer}i" "%{User-Agent}i" %T
例子:
use actix_web::middleware::Logger; use env_logger::Env; #[actix_web::main] async fn main() -> std::io::Result<()> { use actix_web::{App, HttpServer}; env_logger::init_from_env(Env::default().default_filter_or("info")); HttpServer::new(|| { App::new() .wrap(Logger::default()) .wrap(Logger::new("%a %{User-Agent}i")) }) .bind(("127.0.0.1", 8080))? .run() .await }
日志格式
INFO:actix_web::middleware::logger: 127.0.0.1:59934 [02/Dec/2017:00:21:43 -0800] "GET / HTTP/1.1" 302 0 "-" "curl/7.54.0" 0.000397 INFO:actix_web::middleware::logger: 127.0.0.1:59947 [02/Dec/2017:00:22:40 -0800] "GET /index.html HTTP/1.1" 200 0 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:57.0) Gecko/20100101 Firefox/57.0" 0.000646
見日志篇章
Default headers
要設(shè)置默認的響應(yīng)頭,我們可以使用 DefaultHeaders 中間件。如果響應(yīng)頭已經(jīng)包含指定的頭,DefaultHeaders 中間件不會設(shè)置頭。
use actix_web::{http::Method, middleware, web, App, HttpResponse, HttpServer}; #[actix_web::main] async fn main() -> std::io::Result<()> { HttpServer::new(|| { App::new() .wrap(middleware::DefaultHeaders::new().add(("X-Version", "0.2"))) .service( web::resource("/test") .route(web::get().to(HttpResponse::Ok)) .route(web::method(Method::HEAD).to(HttpResponse::MethodNotAllowed)), ) }) .bind(("127.0.0.1", 8080))? .run() .await }
用戶會話
Actix Web 提供了會話管理的通用解決方案,使用 actix-session 中間件可以使用多種后段類型來存儲會話數(shù)據(jù)。默認實現(xiàn)cookie會話后段,也可以添加其他后段實現(xiàn)。
CookieSession 使用 cookie 作為會話存儲,CookieSessionBackend 創(chuàng)建的會話唄限制為存儲少于4000字節(jié)的數(shù)據(jù),因為 payload 必須適合單個 cookie,如果會話長度超過 4000 字節(jié),會產(chǎn)生服務(wù)器內(nèi)部錯誤。
可能具有已簽名或私有的安全策略,每個都有一個各自的 CookieSession 構(gòu)造器。
簽名的 cookie 可以被查看,但不能被客戶端修改,客戶端既不能查看也不能修改私有 cookie。構(gòu)造函數(shù)接受一個鍵作為參數(shù),這是 cookie 會話的私鑰——當這個值被改變,所有會話數(shù)據(jù)都會消失。
通常,您可以創(chuàng)建 SessionStorage 中間件并使用特定的后段實現(xiàn)(如 cookiesession)對其進行初始化,要訪問會話數(shù)據(jù),必須使用會話提取器,這個方法返回一個Session 對象,它允許我們獲取或設(shè)置會話數(shù)據(jù)。
1、添加依賴
cargo add actix-session
2、例子代碼
use actix_session::{Session, SessionMiddleware, storage::CookieSessionStore}; use actix_web::{web, App, Error, HttpResponse, HttpServer, cookie::Key}; async fn index(session: Session) -> Result<HttpResponse, Error> { // access session data if let Some(count) = session.get::<i32>("counter")? { session.insert("counter", count + 1)?; } else { session.insert("counter", 1)?; } Ok(HttpResponse::Ok().body(format!( "Count is {:?}!", session.get::<i32>("counter")?.unwrap() ))) } #[actix_web::main] async fn main() -> std::io::Result<()> { HttpServer::new(|| { App::new() .wrap( // create cookie based session middleware SessionMiddleware::builder(CookieSessionStore::default(), Key::from(&[0; 64])) .cookie_secure(false) .build() ) .service(web::resource("/").to(index)) }) .bind(("127.0.0.1", 8080))? .run() .await }
錯誤處理
ErrorHandlers 中間件允許我們?yōu)轫憫?yīng)提供自定義處理程序,您可以使用 ErrorHandlers::handler 方法為特定狀態(tài)碼注冊自定義錯誤處理程序。您可以修改現(xiàn)有的響應(yīng)或創(chuàng)建一個全新的響應(yīng)。錯誤處理程序可以立即返回響應(yīng),也可以返回解析為響應(yīng)的future。
use actix_web::middleware::{ErrorHandlerResponse, ErrorHandlers}; use actix_web::{ dev, http::{header, StatusCode}, web, App, HttpResponse, HttpServer, Result, }; fn add_error_header<B>(mut res: dev::ServiceResponse<B>) -> Result<ErrorHandlerResponse<B>> { res.response_mut().headers_mut().insert( header::CONTENT_TYPE, header::HeaderValue::from_static("Error"), ); Ok(ErrorHandlerResponse::Response(res.map_into_left_body())) } #[actix_web::main] async fn main() -> std::io::Result<()> { HttpServer::new(|| { App::new() .wrap( ErrorHandlers::new() .handler(StatusCode::INTERNAL_SERVER_ERROR, add_error_header), ) .service(web::resource("/").route(web::get().to(HttpResponse::InternalServerError))) }) .bind(("127.0.0.1", 8080))? .run() .await }
use actix_web::middleware::{ErrorHandlerResponse, ErrorHandlers}; use actix_web::{ dev, http::{header}, }; fn add_error_header<B>(mut res: dev::ServiceResponse<B>) -> Result<ErrorHandlerResponse<B>> { res.response_mut().headers_mut().insert( header::CONTENT_TYPE, header::HeaderValue::from_static("Error"), ); Ok(ErrorHandlerResponse::Response(res.map_into_left_body())) } pub async fn web() { HttpServer::new(|| { App::new() .wrap( ErrorHandlers::new() .handler(StatusCode::NOT_FOUND, add_error_header), ) .service(web::resource("/found").route(web::get().to(HttpResponse::NotFound))) }) .bind(("127.0.0.1", 18080)) .unwrap() .run() .await .unwrap(); }
$ curl -v --location --request GET 'http://127.0.0.1:18080/a/found' Note: Unnecessary use of -X or --request, GET is already inferred. * Trying 127.0.0.1:18080... * Connected to 127.0.0.1 (127.0.0.1) port 18080 (#0) > GET /a/found HTTP/1.1 > Host: 127.0.0.1:18080 > User-Agent: curl/7.79.1 > Accept: */* > * Mark bundle as not supporting multiuse < HTTP/1.1 404 Not Found < content-length: 0 < content-type: Error < date: Fri, 10 Nov 2023 10:01:50 GMT < * Connection #0 to host 127.0.0.1 left intact
以上就是rust 中間件在項目中的使用實戰(zhàn)的詳細內(nèi)容,更多關(guān)于rust 中間件的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Rust循環(huán)控制結(jié)構(gòu)用法詳解
Rust提供了多種形式的循環(huán)結(jié)構(gòu),每種都適用于不同的場景,在Rust中,循環(huán)有三種主要的形式:loop、while和for,本文將介紹Rust中的這三種循環(huán),并通過實例展示它們的用法和靈活性,感興趣的朋友一起看看吧2024-02-02關(guān)于Rust命令行參數(shù)解析以minigrep為例
本文介紹了如何使用Rust的std::env::args函數(shù)來解析命令行參數(shù),并展示了如何將這些參數(shù)存儲在變量中,隨后,提到了處理文件和搜索邏輯的步驟,包括讀取文件內(nèi)容、搜索匹配項和輸出搜索結(jié)果,最后,總結(jié)了Rust標準庫在命令行參數(shù)處理中的便捷性和社區(qū)資源的支持2025-02-02