微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

使用actix文件提供静态文件时如何设置“过期”或“缓存控制”标头?

如何解决使用actix文件提供静态文件时如何设置“过期”或“缓存控制”标头?

我想使用 actix_files静态文件设置缓存 TTL。

就像在 Nginx 配置中:expires max;添加这样的标头:expires: Thu,31 Dec 2037 23:55:55 GMT

如何使用 actix_files 来实现?

use actix_files::Files;
use actix_web::{App,HttpServer,web,HttpResponse,http,cookie,middleware};

#[actix_web::main]
async fn main() {
    HttpServer::new(move || {
        App::new()
            .wrap(middleware::Logger::default())
            .wrap(middleware::Compress::default())
            .service(Files::new("/dist","dist/"))
    })
        .bind("0.0.0.0:8080").unwrap()
        .run()
        .await.unwrap();
}

解决方法

我建议的方法是通过 middleware。 使用 .wrap_fn 可以减少此代码的冗长。

use actix_files::Files;
use actix_service::{Service,Transform};
use actix_web::{
    dev::ServiceRequest,dev::ServiceResponse,http::header::{HeaderValue,EXPIRES},middleware,web,App,Error,HttpServer,};
// use actix_http::http::header::Expires;
use futures::{
    future::{ok,Ready},Future,};

use std::pin::Pin;
use std::task::{Context,Poll};

struct MyCacheInterceptor;

impl<S,B> Transform<S> for MyCacheInterceptor
where
    S: Service<Request = ServiceRequest,Response = ServiceResponse<B>,Error = Error>,S::Future: 'static,B: 'static,{
    type Request = ServiceRequest;
    type Response = ServiceResponse<B>;
    type Error = Error;
    type InitError = ();
    type Transform = MyCacheInterceptorMiddleware<S>;
    type Future = Ready<Result<Self::Transform,Self::InitError>>;

    fn new_transform(&self,service: S) -> Self::Future {
        ok(MyCacheInterceptorMiddleware { service })
    }
}

pub struct MyCacheInterceptorMiddleware<S> {
    service: S,}

impl<S,B> Service for MyCacheInterceptorMiddleware<S>
where
    S: Service<Request = ServiceRequest,{
    type Request = ServiceRequest;
    type Response = ServiceResponse<B>;
    type Error = Error;
    type Future = Pin<Box<dyn Future<Output = Result<Self::Response,Self::Error>>>>;

    fn poll_ready(&mut self,cx: &mut Context<'_>) -> Poll<Result<(),Self::Error>> {
        self.service.poll_ready(cx)
    }

    fn call(&mut self,req: ServiceRequest) -> Self::Future {
        let fut = self.service.call(req);

        Box::pin(async move {
            let mut res = fut.await?;
            let headers = res.headers_mut();
            headers.append(
                EXPIRES,HeaderValue::from_static("Thu,31 Dec 2037 23:55:55 GMT"),);
            return Ok(res);
        })
    }
}

#[actix_web::main]
async fn main() {
    HttpServer::new(move || {
        App::new()
            .wrap(middleware::Logger::default())
            .wrap(middleware::Compress::default())
            .service(
                web::scope("/dist")
                    .wrap(MyCacheInterceptor)
                    .service(Files::new("",".").show_files_listing()),)
    })
    .bind("0.0.0.0:8080")
    .unwrap()
    .run()
    .await
    .unwrap();
}

#[cfg(test)]
mod tests {
    use super::*;
    use actix_web::{test,App};

    #[actix_rt::test]
    async fn test_expire_header() {
        let mut app = test::init_service(
            App::new().service(
                web::scope("/")
                    .wrap(MyCacheInterceptor)
                    .service(Files::new("",),)
        .await;
        let req = test::TestRequest::with_header("content-type","text/plain").to_request();
        let resp = test::call_service(&mut app,req).await;
        assert!(resp.status().is_success());
        assert!(resp.headers().get(EXPIRES).is_some());
        assert_eq!(
            resp.headers().get(EXPIRES).unwrap(),);
    }
}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。