在本站中
本站是开源的,仓库在 yuxuetr/rustineverything。这一部分的链接都指向同一个提交 89a61b1(2026-10-23),行号以它为准。站点 app 用的是 axum 0.8.9、tower 0.5.3、tower-http 0.6.11(以该提交的 Cargo.lock 为准)。app 的运行时代码不直接 use tower:tower 只出现在 [dev-dependencies] 里,给测试用。生产路径上的 tower 都是经由 axum 和 tower-http 间接用到的。
- 中间件栈:
main.rs里四次Router::layer,后加的在外层。安全头挂在最外面,因为限流的 429 和尾斜杠跳转都是短路返回,只有包在它们外面的层才看得到这些响应。限流是手写的按 IP 令牌桶,不用tower::limit::RateLimit:后者超限时让调用方等而不是拒绝,整个实例共用一个窗口,没有Clone,而且 axum 每个请求都会复制一份服务。最后对比网关(Pingora)的钩子式写法。 - 不起服务器的测试:tower-http 的
ServeDir本身是一个Service,nest_service直接挂上路由。Router也是Service,测试里用ServiceExt::oneshot发一个请求,不监听端口。还有一处要留意:没with_state的Router每个请求都会把 handler 外面的 layer 重新套一遍,带状态的 layer 在 oneshot 测试里和线上表现不一样。
flowchart TB req[HTTP 请求] --> sec[security_headers_mw] sec --> comp[CompressionLayer] comp --> slash[trailing_slash_mw] slash --> rl[rate_limit_mw] rl --> routes[路由] routes --> page[页面与 server fn] routes --> dir["ServeDir(nest_service)"] tst["测试:oneshot"] -.-> routes
💬 关联讨论
发起讨论加载中...