中间件和钩子宏
2025/11/29大约 6 分钟hyperlane-macros
中间件和钩子宏
中间件和钩子宏提供了强大的请求处理管道机制,允许在请求处理的不同阶段插入自定义逻辑。这些宏支持中间件注册、钩子执行、组合宏等功能。
核心配置宏
#[hyperlane]
定义 hyperlane 服务器实例和配置。
用法
use hyperlane::*;
use hyperlane_macros::*;
#[hyperlane(server: Server)]
#[hyperlane(config: ServerConfig)]
#[tokio::main]
async fn main() {
config.disable_nodelay().await;
server.config(config).await;
let server_hook: ServerControlHook = server.run().await.unwrap_or_default();
server_hook.wait().await;
}说明
- 接受
variable_name: Type格式的参数 - 变量在函数作用域中可用,为指定类型的实例
- 用于定义服务器实例和配置
- 必须在其他依赖宏之前使用
#[route]
注册函数为路由处理器。
用法
use hyperlane::*;
use hyperlane_macros::*;
#[route("/response")]
struct Response;
impl ServerHook for Response {
async fn new(_ctx: &Context) -> Self {
Self
}
#[response_body("response")]
async fn handle(self, ctx: &Context) {}
}参数
path: 定义路由路径的字符串字面量
说明
- 注册装饰函数为给定路径的路由处理器
- 需要
#[hyperlane(server: Server)]宏定义服务器实例 - 支持路径参数:
/user/:id - 支持通配符:
/static/*
中间件注册
#[request_middleware]
注册请求中间件。
用法
use hyperlane::*;
use hyperlane_macros::*;
#[request_middleware]
struct RequestMiddleware;
impl ServerHook for RequestMiddleware {
async fn new(_ctx: &Context) -> Self {
Self
}
#[prologue_macros(
response_status_code(200),
response_version(HttpVersion::HTTP1_1),
response_header(SERVER => HYPERLANE)
)]
async fn handle(self, ctx: &Context) {}
}带优先级的用法
#[request_middleware(1)]
struct PriorityRequestMiddleware;
impl ServerHook for PriorityRequestMiddleware {
async fn new(_ctx: &Context) -> Self {
Self
}
async fn handle(self, ctx: &Context) {
// 请求处理逻辑
}
}说明
- 注册装饰函数为入站请求的中间件
- 需要
#[hyperlane(server: Server)]宏定义服务器实例 - 如果未指定优先级参数,钩子将比指定优先级的钩子具有更高的优先级
- 数值越小,优先级越高
#[response_middleware]
注册响应中间件。
用法
use hyperlane::*;
use hyperlane_macros::*;
#[response_middleware]
struct ResponseMiddleware1;
impl ServerHook for ResponseMiddleware1 {
async fn new(_ctx: &Context) -> Self {
Self
}
async fn handle(self, ctx: &Context) {}
}带优先级的用法
#[response_middleware(2)]
struct ResponseMiddleware2;
impl ServerHook for ResponseMiddleware2 {
async fn new(_ctx: &Context) -> Self {
Self
}
#[prologue_macros(
reject(ctx.get_request().await.is_ws())
)]
async fn handle(self, ctx: &Context) {}
}说明
- 注册装饰函数为出站响应的中间件
- 需要
#[hyperlane(server: Server)]宏定义服务器实例 - 如果未指定优先级参数,钩子将比指定优先级的钩子具有更高的优先级
- 在响应发送前执行
异常处理
#[panic_hook]
注册 panic 钩子。
用法
use hyperlane::*;
use hyperlane_macros::*;
#[panic_hook]
#[panic_hook(1)]
#[panic_hook("2")]
struct PanicHook;
impl ServerHook for PanicHook {
async fn new(_ctx: &Context) -> Self {
Self
}
#[epilogue_macros(response_body("panic_hook"), send)]
async fn handle(self, ctx: &Context) {}
}说明
- 注册装饰函数处理请求处理期间发生的 panic
- 需要
#[hyperlane(server: Server)]宏定义服务器实例 - 如果未指定优先级参数,钩子将比指定优先级的钩子具有更高的优先级
- 支持数字或字符串参数作为优先级标识
钩子执行
#[prologue_hooks]
在主处理函数之前执行多个指定的函数。
用法
use hyperlane::*;
use hyperlane_macros::*;
struct PrologueHooks;
impl ServerHook for PrologueHooks {
async fn new(_ctx: &Context) -> Self {
Self
}
#[get]
#[http]
async fn handle(self, _ctx: &Context) {}
}
async fn prologue_hooks_fn(ctx: Context) {
let hook = PrologueHooks::new(&ctx).await;
hook.handle(&ctx).await;
}
#[route("/hook")]
struct Hook;
impl ServerHook for Hook {
async fn new(_ctx: &Context) -> Self {
Self
}
#[prologue_hooks(prologue_hooks_fn)]
#[response_body("Testing hook macro")]
async fn handle(self, ctx: &Context) {}
}说明
- 配置多个前置执行钩子
- 指定的钩子函数将按提供顺序调用,然后执行主函数
- 接受逗号分隔的函数名列表作为参数
- 所有钩子函数和主函数必须接受
Context参数 - 避免在同一函数上与其他宏组合使用,防止宏展开冲突
#[epilogue_hooks]
在主处理函数之后执行多个指定的函数。
用法
use hyperlane::*;
use hyperlane_macros::*;
struct EpilogueHooks;
impl ServerHook for EpilogueHooks {
async fn new(_ctx: &Context) -> Self {
Self
}
#[response_status_code(200)]
async fn handle(self, ctx: &Context) {}
}
async fn epilogue_hooks_fn(ctx: Context) {
let hook = EpilogueHooks::new(&ctx).await;
hook.handle(&ctx).await;
}
#[route("/hook")]
struct Hook;
impl ServerHook for Hook {
async fn new(_ctx: &Context) -> Self {
Self
}
#[epilogue_hooks(epilogue_hooks_fn)]
#[response_body("Testing hook macro")]
async fn handle(self, ctx: &Context) {}
}说明
- 配置多个后置执行钩子
- 主函数首先执行,然后按提供顺序执行指定的钩子函数
- 接受逗号分隔的函数名列表作为参数
- 所有钩子函数和主函数必须接受
Context参数 - 避免在同一函数上与其他宏组合使用
组合宏
#[prologue_macros]
在装饰函数前注入多个宏。
用法
use hyperlane::*;
use hyperlane_macros::*;
#[route("/post")]
struct Post;
impl ServerHook for Post {
async fn new(_ctx: &Context) -> Self {
Self
}
#[prologue_macros(post, response_body("post"), send_once)]
async fn handle(self, ctx: &Context) {}
}说明
- 宏按头插入顺序应用,列表中的第一个宏是最外层的宏
- 支持多个宏的组合,用逗号分隔
- 简化了多个前置宏的使用
- 提供了更清晰的宏组织方式
#[epilogue_macros]
在装饰函数后注入多个宏。
用法
use hyperlane::*;
use hyperlane_macros::*;
#[response_middleware(2)]
struct ResponseMiddleware2;
impl ServerHook for ResponseMiddleware2 {
async fn new(_ctx: &Context) -> Self {
Self
}
#[epilogue_macros(send, flush)]
async fn handle(self, ctx: &Context) {}
}说明
- 宏按尾插入顺序应用,列表中的最后一个宏是最外层的宏
- 支持多个宏的组合,用逗号分隔
- 简化了多个后置宏的使用
- 提供了更清晰的宏组织方式
依赖注入
#[inject]
创建指定类型的新实例并赋予变量名。
用法
use hyperlane::*;
use hyperlane_macros::*;
#[hyperlane(server: Server)]
#[hyperlane(config: ServerConfig)]
#[tokio::main]
async fn main() {
#[inject(service: UserService)]
async fn handle_request(ctx: &Context) {
// 使用 service 实例
}
}说明
- 接受
variable_name: Type格式的参数 - 在函数开始时生成实例初始化
- 变量在函数作用域中可用,为指定类型的实例
- 支持依赖注入模式
中间件示例
请求日志中间件
use hyperlane::*;
use hyperlane_macros::*;
#[request_middleware(1)]
struct RequestLogger;
impl ServerHook for RequestLogger {
async fn new(_ctx: &Context) -> Self {
Self
}
#[prologue_macros(
request_path(path),
request_method(method),
request_headers(headers)
)]
async fn handle(self, ctx: &Context) {
log::info!("Request: {} {} - Headers: {:?}", method, path, headers);
}
}响应缓存中间件
#[response_middleware(2)]
struct CacheMiddleware;
impl ServerHook for CacheMiddleware {
async fn new(_ctx: &Context) -> Self {
Self
}
#[prologue_macros(
request_path(path),
response_body(body)
)]
async fn handle(self, ctx: &Context) {
if should_cache(path) {
cache_response(path, body).await;
}
}
}认证中间件
#[request_middleware(10)]
struct AuthMiddleware;
impl ServerHook for AuthMiddleware {
async fn new(_ctx: &Context) -> Self {
Self
}
#[prologue_macros(
request_header("Authorization" => auth_header),
reject(is_unauthorized(auth_header))
)]
async fn handle(self, ctx: &Context) {
validate_token(auth_header).await;
}
}钩子链示例
完整的请求处理链
use hyperlane::*;
use hyperlane_macros::*;
// 1. 请求中间件
#[request_middleware(1)]
struct LoggingMiddleware;
#[request_middleware(5)]
struct AuthMiddleware;
#[request_middleware(10)]
struct ValidationMiddleware;
// 2. 路由处理器
#[route("/api/data")]
struct DataHandler;
impl ServerHook for DataHandler {
async fn new(_ctx: &Context) -> Self {
Self
}
#[prologue_hooks(validation_hook, auth_hook)]
#[epilogue_hooks(audit_hook)]
#[prologue_macros(
http,
methods(get, post),
request_body(body)
)]
#[epilogue_macros(
response_status_code(200),
response_header("Content-Type", "application/json"),
response_body(&process_data(body)),
send
)]
async fn handle(self, ctx: &Context) {}
}
// 3. 响应中间件
#[response_middleware(1)]
struct CompressionMiddleware;
#[response_middleware(5)]
struct SecurityHeadersMiddleware;
// 4. Panic 处理
#[panic_hook(1)]
struct ErrorRecovery;使用建议
中间件设计原则:
- 保持中间件单一职责
- 避免在中间件中执行耗时操作
- 合理设置中间件优先级
- 确保中间件的幂等性
钩子使用策略:
- 使用前置钩子进行请求预处理
- 使用后置钩子进行响应后处理
- 避免钩子间的循环依赖
- 合理组织钩子的执行顺序
错误处理:
- 在中间件中统一处理错误
- 使用 panic 钩子处理异常
- 提供详细的错误日志
- 实现优雅的错误恢复
性能考虑:
- 优化中间件的执行顺序
- 避免不必要的中间件
- 使用缓存减少重复计算
- 监控中间件的性能影响
测试策略:
- 单独测试每个中间件
- 测试中间件的组合效果
- 模拟各种错误场景
- 验证钩子的执行顺序
维护性:
- 清晰的中间件文档
- 合理的中间件分组
- 版本兼容性考虑
- 渐进式迁移策略