您的位置:首页 > 汽车 > 新车 > 个人小程序怎么做_抖音小程序电脑上怎么打开_前端优化_太原网站关键词推广

个人小程序怎么做_抖音小程序电脑上怎么打开_前端优化_太原网站关键词推广

2024/12/23 12:25:45 来源:https://blog.csdn.net/allenlu2008/article/details/144446612  浏览:    关键词:个人小程序怎么做_抖音小程序电脑上怎么打开_前端优化_太原网站关键词推广
个人小程序怎么做_抖音小程序电脑上怎么打开_前端优化_太原网站关键词推广

actix_web::middleware 在 Actix Web 框架中扮演着重要的角色,它允许开发者在处理 HTTP 请求和响应的过程中插入自定义的逻辑。中间件可以在请求到达处理函数之前或响应返回给客户端之前执行,从而实现日志记录、身份验证、数据验证、错误处理等功能。

为什么要有中间件?

代码在处理逻辑的时候,通常只处理正常的业务逻辑,而在处理过程中,可能会遇到一些特殊的情况,比如:404错误,这种错误会让客户端的请求无法进入到代码功能中,这时候就需要中间件来处理这些特殊的情况。

另外,还可以起到Java里面的过滤器功能,在Java里面,过滤器可以在请求到达处理函数之前或响应返回给客户端之前执行,从而实现对请求和响应的预处理和后处理。

在Rust开发中,特别是在使用Actix Web框架时,中间件(middleware)是一种非常有用的设计模式,它允许开发者在处理HTTP请求和响应的过程中插入自定义的逻辑。以下是使用中间件的几个主要原因:

  • 代码模块化和可重用性:中间件可以将通用的功能(如日志记录、身份验证、数据验证等)封装起来,使得这些功能可以被多个处理函数共享和重用。这样可以减少代码重复,提高代码的可读性和可维护性。

  • 灵活性和可扩展性:通过使用中间件,开发者可以灵活地组合和配置不同的功能,以满足应用程序的特定需求。例如,可以根据不同的路由或用户角色应用不同的中间件。

  • 请求和响应的预处理和后处理:中间件可以在请求到达处理函数之前或响应返回给客户端之前执行,从而实现对请求和响应的预处理和后处理。例如,可以在请求到达之前记录日志、验证用户身份,或者在响应返回之前压缩数据、添加额外的头部信息等。

  • 提高开发效率:使用中间件可以减少开发者编写重复代码的工作量,使得开发者可以更专注于业务逻辑的实现。同时,中间件的模块化设计也使得代码的测试和调试更加容易。

  • 支持异步编程模型:Actix Web是一个基于异步IO的Web框架,中间件可以很好地适应这种编程模型,允许开发者在不阻塞主线程的情况下执行耗时的操作。

以下是一些常见的中间件及其作用:

  • 日志记录:记录每个请求的详细信息,如请求方法、路径、时间戳等,有助于调试和监控。
  • 身份验证:验证用户的身份,确保只有经过授权的用户才能访问特定的资源或执行特定的操作。
  • 数据验证:在请求到达处理函数之前,验证请求数据的格式和内容是否符合预期,防止无效或恶意数据进入系统。
  • 错误处理:统一处理应用程序中的错误,提供友好的错误信息给客户端,同时记录错误日志以便后续分析。
  • 性能监控:测量每个请求的处理时间,帮助开发者识别性能瓶颈并进行优化。
  • 跨域资源共享(CORS):处理跨域请求,允许或拒绝来自不同域的请求,确保安全的跨域数据交互。
  • 使用中间件可以使代码更加模块化和可重用,开发者可以根据需要组合和配置不同的中间件,以满足应用程序的特定需求。在 Actix Web 中,中间件通常通过 App::wrap 方法进行注册和应用。

自定义中间件的过程:

利用闭包实现简单的中间件

例如我要定义一个预先获取请求中header里面的token,如果没有这个token则直接就返回错误。代码可以这样写:

use actix_web::dev::Service;
use actix_web::error;
use actix_web::{middleware::{self, Logger}, web, App, HttpServer};
#[actix_web::main]
async fn main() -> std::io::Result<()> {HttpServer::new(move || {App::new().wrap(middleware::Logger::default()).wrap_fn(|req, srv| {let header = req.headers().to_owned();let fut = srv.call(req);async move {let res = fut.await;match header.get("token"){Some(token) => {println!("token:{}", token.to_str().unwrap());},None => {println!("token is None");return Err(error::ErrorUnauthorized("Unauthorized"));},}res}}).route("/", web::get().to(|| async { "Hello, World!" }))}).bind("127.0.0.1:8080")?.run().await
}

这里的核心,是使用wrap_fn + 一个闭包来实现中间件。

在示例代码中,wrap_fn 被用来创建一个中间件,这个中间件检查请求头中是否包含 token。如果没有 token,它会返回一个未经授权的错误。如果有 token,它会调用下一个服务并返回其结果。

warp_fn的源码如下(看不懂也没关系,不用懂,我写这里是为了你以后能看懂时候回来查资料用的)

pub fn wrap_fn<F, Fut>(f: F) -> impl Transform<ServiceRequest, Response = ServiceResponse<Fut::Item>, Error = Fut::Error, InitError = ()>
whereF: Fn(ServiceRequest, &mut dyn Service<ServiceRequest, Response = ServiceResponse<Fut::Item>, Error = Fut::Error, Future = Fut>) -> Fut,Fut: Future<Output = Result<ServiceResponse<Fut::Item>, Fut::Error>> + 'static,

里面参数解释如下:

  • 输入参数:

    • F: 这是一个函数类型,它接受两个参数:ServiceRequest 和一个可变引用 &mut dyn Service<...>。这个函数将返回一个 Fut 类型的 Future。
    • Fut: 这是一个 Future 类型,它的输出是 Result<ServiceResponseFut::Item, Fut::Error>。Fut::Item 是响应体的类型,Fut::Error 是错误类型。
  • 返回值:

    • impl Transform<ServiceRequest, Response = ServiceResponseFut::Item, Error = Fut::Error, InitError = ()>: 这是一个实现了 Transform trait 的类型,它可以转换 ServiceRequest 到 ServiceResponseFut::Item,并且可以处理 Fut::Error 类型的错误。

执行结果如下:

如果是一些建议的逻辑,我们用wrap_fn + 闭包就可以了,但是如果是一些复杂的逻辑,就需要自己实现Transform trait了。

重新实现Transform trait 来实现自定义的中间件

  1. 中间件初始化:在这个阶段,中间件工厂函数被调用,它接收链中的下一个服务作为参数。这允许中间件在实际处理请求之前进行任何必要的设置或配置。
  • 中间件工厂类是 Transform trait的。
    • S - 后续服务的类型:S 代表链中下一个服务的类型,即当前中间件将请求传递给哪个服务。
    • B - 响应体的类型:B 代表响应体(response)的类型,指定了从服务返回的响应内容的格式。
//中间的工厂类
pub struct Auth;impl<S, B> Transform<S, ServiceRequest> for Auth
whereS: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,S::Future: 'static,B: 'static,
{type Response = ServiceResponse<B>;type Error = Error;type InitError = ();type Transform = AuthMiddleware<S>;type Future = Ready<Result<Self::Transform, Self::InitError>>;fn new_transform(&self, service: S) -> Self::Future {ready(Ok(AuthMiddleware { service }))}
}
  1. 编写中间件的具体实现,核心是中间件的 call 方法调用:一旦中间件初始化完成,每当有新的请求到来时,中间件的 call 方法就会被调用,并接收这个普通请求作为参数。此时,中间件可以对请求进行处理

// 中间件的具体实现,里面需要接受工厂类里面过来的service
pub struct AuthMiddleware<S> {service: S,
}//具体实现
//核心是两个方法:
// call 具体实现
// poll_ready
impl<S, B> Service<ServiceRequest> for AuthMiddleware<S>
whereS: 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>>;// 实现 poll_ready 方法,用于检查服务是否准备好处理请求 //这里用的是forward_ready!宏forward_ready!(service);// 实现 call 方法,用于处理实际的请求fn call(&self, req: ServiceRequest) -> Self::Future {// 进行鉴权操作,判断是否有权限if has_permission(&req) {// 有权限,继续执行后续中间件let fut = self.service.call(req);Box::pin(async move {let res = fut.await?;Ok(res)})} else {// 没有权限,立即返回响应Box::pin(async move {// 鉴权失败,返回未授权的响应,停止后续中间件的调用Err(error::ErrorUnauthorized("Unauthorized"))})}}
}fn has_permission(req: &ServiceRequest) -> bool {// 实现你的鉴权逻辑,根据需求判断是否有权限// 返回 true 表示有权限,返回 false 表示没有权限// unimplemented!()let value = HeaderValue::from_str("").unwrap();match req.path().to_ascii_lowercase().as_str(){"/login" => true,_ => {let token = req.headers().get("token").unwrap_or(&value);if token.len() <=0{false}else{println!("验证一下token,看看是否合法");true}}}
}

核心方法说明:

  • poll_ready: 这个方法用于检查服务是否准备好处理请求。 它返回一个Poll类型的结果,表示服务是否就绪。 如果服务已经就绪,返回Poll::Ready(Ok(()))。 如果服务尚未就绪,返回Poll::Pending,表示需要等待一段时间后再次检查。 在middleware中,poll_ready方法通常用于确保在处理请求之前,所有依赖的资源或服务都已经准备就绪。

  • call: 这个方法用于处理实际的请求。 它接收一个ServiceRequest类型的参数,并返回一个ServiceResponse类型的结果。 在middleware中,call方法通常用于对请求进行预处理或后处理,例如添加日志记录、验证请求、修改响应等。 call方法的返回值是一个Future,表示异步处理的结果。

所以也可以自己实现poll_ready

fn poll_ready(&self, ctx: &mut core::task::Context<'_>) -> std::task::Poll<Result<(), Self::Error>> {if self.service.poll_ready(ctx).is_pending() {// 如果服务尚未准备好,返回Pendingreturn std::task::Poll::Pending;}// 如果服务已准备好,返回Ready(Ok(()))std::task::Poll::Ready(Ok(()))
}

使用中间件

#[actix_web::main]
async fn main() -> std::io::Result<()> {//中间件的顺序是从下到上的,最后注册的中间件会最先执行HttpServer::new(move || {App::new().wrap(middleware::Logger::default()).wrap(Auth::Auth)// 注册其他路由和处理函数.route("/", web::get().to(|| async { "Hello, World!" })).route("/login", web::get().to(|| async { "Hello, login" }))}).bind("127.0.0.1:8080")?.run().await
}

执行结果如下:

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com