1 个不稳定版本
0.1.0 | 2023年10月7日 |
---|
#19 在 #tower-middleware
46KB
916 行
tower-etag-cache
快速入门
提供const-lru支持的CacheProvider
实现,可直接使用。
use axum::{error_handling::HandleErrorLayer, http::StatusCode, BoxError, Router};
use tower_etag_cache::{const_lru_provider::ConstLruProvider, EtagCacheLayer};
use tower_http::services::{ServeDir, ServeFile};
#[tokio::main]
pub async fn main() {
let app = Router::new()
.fallback_service(ServeDir::new("app").fallback(ServeFile::new("app/404.html")))
.layer(
ServiceBuilder::new()
.layer(HandleErrorLayer::new(handle_etag_cache_layer_err))
.layer(EtagCacheLayer::with_default_predicate(
ConstLruProvider::<_, _, 255, u8>::init(5),
)),
);
axum::Server::bind(&"0.0.0.0:3000".parse().unwrap())
.serve(app.into_make_service())
.await
.unwrap();
}
async fn handle_etag_cache_layer_err<T: Into<BoxError>>(err: T) -> (StatusCode, String) {
(StatusCode::INTERNAL_SERVER_ERROR, err.into().to_string())
}
ConstLruProvider
将响应体的base64编码的blake3哈希值作为ETag。
它通过SimpleEtagCacheKey
来键入条目,这是一个由请求URI + 排序后的请求头值集合组成的结构,包括Accept
、Accept-Language
和Accept-Encoding
请求头。这使得它根据这些头信息来改变ETag。
由于当前实现将整个响应体加载到内存中以便计算ETag,因此ConstLruProvider
不适用于像大文件这样的大响应。
工作原理
使用内部tower服务 + 实现CacheProvider
特质的任何类型创建EtagCache
tower服务和EtagCacheLayer
tower层。
- 包含2个tower服务
- 1个在传入的HTTP请求上运行,以查找ETag,检查请求的
If-None-Match
是否与缓存中的ETag匹配 - 1 在出站HTTP响应上运行,以计算和保存响应的ETag
- 1个在传入的HTTP请求上运行,以查找ETag,检查请求的
- 有一个关联的缓存键类型,用于标识缓存条目
- 有一个关联的转换响应体类型,它会在ETag计算和保存程序后,将出站HTTP响应体转换为该类型
pub trait CacheProvider<ReqBody, ResBody>:
Service<http::Request<ReqBody>, Response = CacheGetResponse<ReqBody, Self::Key>> // runs on request
+ Service<(Self::Key, http::Response<ResBody>), Response = http::Response<Self::TResBody>> // runs on response
{
type Key;
type TResBody;
}
当一个HTTP请求到来时,
- 如果服务的passthrough_predicate指示请求应该被传递,则未经修改的请求将被直接传递到内部服务,并将响应直接返回给客户端。
- 否则,
CacheProvider
的第一个ETag查找服务将在请求上运行。 - 如果服务返回缓存命中,则向客户端返回一个带有相关头部的空HTTP 304响应。
- 否则,内部服务将在未经修改的请求上运行。
- 如果服务器的passthrough_predicate指示响应应该被传递,则未经修改的响应将返回给客户端。
- 否则,
CacheProvider
的第二个ETag计算和保存服务将在内部服务返回的HTTP响应上运行。 - 服务转换响应体,并修改响应头以包含保存的ETag和其他相关头,并将其返回给客户端。
PassthroughPredicate
PassthroughPredicate
特性控制何时请求和响应应忽略缓存层。
提供的 DefaultPredicate
可用于与 EtagCacheLayer::with_default_predicate
一起使用,并具有以下行为
请求
- 只有
GET
和HEAD
方法会通过缓存层运行
响应
- 只有
HTTP 2XX
响应会被缓存,不包括204 No Content
- 只有那些还没有
ETag
头部的响应会被缓存 - 只有那些具有缺失、无效或非零
Content-Length
头部的响应会被缓存
依赖
~0.8–3.5MB
~67K SLoC