hyperlane-macros
2025/11/10大约 16 分钟hyperlane-macros
一个用于构建具有增强功能的 HTTP 服务器的综合性过程宏集合。该 crate 提供了属性宏,可简化 HTTP 请求处理、协议验证、响应管理和请求数据提取。
安装
要使用此 crate,您可以运行 cmd:
cargo add hyperlane-macros可用宏
Hyperlane 宏
#[hyperlane(server: Server)]- 创建一个名为Server的新实例,指定变量名和类型,并自动注册 crate 内定义的其他钩子和路由。#[hyperlane(config: ServerConfig)]- 创建一个名为ServerConfig的新实例,指定变量名和类型。#[hyperlane(var1: Type1, var2: Type2, ...)]- 支持在单次调用中初始化多个实例
HTTP 方法宏
#[methods(method1, method2, ...)]- 接受多个 HTTP 方法#[get]- GET 方法处理器#[post]- POST 方法处理器#[put]- PUT 方法处理器#[delete]- DELETE 方法处理器#[patch]- PATCH 方法处理器#[head]- HEAD 方法处理器#[options]- OPTIONS 方法处理器#[connect]- CONNECT 方法处理器#[trace]- TRACE 方法处理器
协议检查宏
#[ws]- WebSocket 检查,确保函数仅在 WebSocket 升级请求时执行#[http]- HTTP 检查,确保函数仅在标准 HTTP 请求时执行#[h2c]- HTTP/2 明文检查,确保函数仅在 HTTP/2 明文请求时执行#[http0_9]- HTTP/0.9 检查,确保函数仅在 HTTP/0.9 协议请求时执行#[http1_0]- HTTP/1.0 检查,确保函数仅在 HTTP/1.0 协议请求时执行#[http1_1]- HTTP/1.1 检查,确保函数仅在 HTTP/1.1 协议请求时执行#[http1_1_or_higher]- HTTP/1.1 或更高版本检查,确保函数仅在 HTTP/1.1 或更新协议版本时执行#[http2]- HTTP/2 检查,确保函数仅在 HTTP/2 协议请求时执行#[http3]- HTTP/3 检查,确保函数仅在 HTTP/3 协议请求时执行#[tls]- TLS 检查,确保函数仅在 TLS 加密连接时执行
响应设置宏
#[response_status_code(code)]- 设置响应状态码(支持字面量和全局常量)#[response_reason_phrase("phrase")]- 设置响应原因短语(支持字面量和全局常量)#[response_header("key", "value")]- 添加响应头(支持字面量和全局常量)#[response_header("key" => "value")]- 设置响应头(支持字面量和全局常量)#[response_body("data")]- 设置响应体(支持字面量和全局常量)#[response_version(version)]- 设置响应 HTTP 版本(支持字面量和全局常量)#[clear_response_headers]- 清除所有响应头
发送操作宏
#[send]- 函数执行后发送完整响应(包含头部和体)#[send_body]- 函数执行后仅发送响应体#[send_once]- 函数执行后恰好发送一次完整响应#[send_body_once]- 函数执行后恰好发送一次响应体#[send_with_data("data")]- 函数执行后发送包含指定数据的完整响应#[send_once_with_data("data")]- 函数执行后恰好发送一次包含指定数据的完整响应#[send_body_with_data("data")]- 函数执行后发送包含指定数据的响应体
刷新宏
#[flush]- 函数执行后刷新响应流,确保数据立即传输
中止宏
#[aborted]- 处理中止的请求,为提前终止的连接提供清理逻辑
关闭操作宏
#[closed]- 处理关闭的流,为已完成的连接提供清理逻辑
条件宏
#[filter(condition)]- 仅当condition(返回布尔值的代码块)为true时继续执行。#[reject(condition)]- 仅当condition(返回布尔值的代码块)为false时继续执行。
请求体宏
#[request_body(variable_name)]- 将原始请求体提取到指定变量中,类型为 RequestBody#[request_body(var1, var2, ...)]- 支持多个请求体变量#[request_body_json(variable_name: type)]- 将请求体解析为 JSON 并存入指定变量和类型#[request_body_json(var1: Type1, var2: Type2, ...)]- 支持多个 JSON 体解析
属性宏
#[attribute(key => variable_name: type)]- 通过键提取特定属性到类型化变量中#[attribute("key1" => var1: Type1, "key2" => var2: Type2, ...)]- 支持多个属性提取
属性宏集合
#[attributes(variable_name)]- 获取所有属性作为 HashMap,用于全面访问属性#[attributes(var1, var2, ...)]- 支持多个属性集合
路由参数宏
#[route_param(key => variable_name)]- 通过键提取特定路由参数到变量中#[route_param("key1" => var1, "key2" => var2, ...)]- 支持多个路由参数提取
路由参数宏集合
#[route_params(variable_name)]- 将所有路由参数作为集合获取#[route_params(var1, var2, ...)]- 支持多个路由参数集合
请求查询宏
#[request_query(key => variable_name)]- 从 URL 查询字符串中通过键提取特定查询参数#[request_query("key1" => var1, "key2" => var2, ...)]- 支持多个查询参数提取
请求查询宏集合
#[request_querys(variable_name)]- 将所有查询参数作为集合获取#[request_querys(var1, var2, ...)]- 支持多个查询参数集合
请求头宏
#[request_header(key => variable_name)]- 从请求中通过名称提取特定 HTTP 头#[request_header(KEY1 => var1, KEY2 => var2, ...)]- 支持多个头提取
请求头宏集合
#[request_headers(variable_name)]- 将所有 HTTP 头作为集合获取#[request_headers(var1, var2, ...)]- 支持多个头集合
请求 Cookie 宏
#[request_cookie(key => variable_name)]- 从请求 Cookie 头中通过键提取特定 Cookie 值#[request_cookie("key1" => var1, "key2" => var2, ...)]- 支持多个 Cookie 提取
请求 Cookies 宏集合
#[request_cookies(variable_name)]- 从 Cookie 头中获取所有 Cookie 作为原始字符串#[request_cookies(var1, var2, ...)]- 支持多个 Cookie 集合
请求版本宏
#[request_version(variable_name)]- 将 HTTP 请求版本提取到变量中#[request_version(var1, var2, ...)]- 支持多个请求版本变量
请求路径宏
#[request_path(variable_name)]- 将 HTTP 请求路径提取到变量中#[request_path(var1, var2, ...)]- 支持多个请求路径变量
主机宏
#[host("hostname")]- 限制函数仅在具有特定主机头值的请求上执行#[host("host1", "host2", ...)]- 支持多个主机检查#[reject_host("hostname")]- 拒绝匹配特定主机头值的请求#[reject_host("host1", "host2", ...)]- 支持多个主机拒绝
Referer 宏
#[referer("url")]- 限制函数仅在具有特定 referer 头值的请求上执行#[referer("url1", "url2", ...)]- 支持多个 referer 检查#[reject_referer("url")]- 拒绝匹配特定 referer 头值的请求#[reject_referer("url1", "url2", ...)]- 支持多个 referer 拒绝
钩子宏
#[prologue_hooks(function_name)]- 在主处理器函数前执行指定函数#[epilogue_hooks(function_name)]- 在主处理器函数后执行指定函数#[panic_hook]- 当服务器内发生 panic 时执行函数#[prologue_macros(macro1, macro2, ...)]- 在装饰函数前注入宏列表。#[epilogue_macros(macro1, macro2, ...)]- 在装饰函数后注入宏列表。
中间件宏
#[request_middleware]- 将函数注册为请求中间件#[request_middleware(order)]- 将函数注册为指定顺序的请求中间件#[response_middleware]- 将函数注册为响应中间件#[response_middleware(order)]- 将函数注册为指定顺序的响应中间件#[panic_hook]- 将函数注册为 panic 钩子#[panic_hook(order)]- 将函数注册为指定顺序的 panic 钩子
流处理宏
#[http_from_stream]- 使用默认缓冲区大小包装函数体进行 HTTP 流处理。仅当成功从 HTTP 流读取数据时才执行函数体。#[http_from_stream(buffer_size)]- 使用指定缓冲区大小包装函数体进行 HTTP 流处理。#[http_from_stream(variable_name)]- 使用指定变量名包装函数体进行 HTTP 流处理,将数据存储在指定变量中。#[http_from_stream(buffer_size, variable_name)]- 使用指定缓冲区大小和变量名包装函数体进行 HTTP 流处理。#[http_from_stream(variable_name, buffer_size)]- 使用指定变量名和缓冲区大小(顺序相反)包装函数体进行 HTTP 流处理。#[ws_from_stream]- 使用默认缓冲区大小包装函数体进行 WebSocket 流处理。仅当成功从 WebSocket 流读取数据时才执行函数体。#[ws_from_stream(buffer_size)]- 使用指定缓冲区大小包装函数体进行 WebSocket 流处理。#[ws_from_stream(variable_name)]- 使用指定变量名包装函数体进行 WebSocket 流处理,将数据存储在指定变量中。#[ws_from_stream(buffer_size, variable_name)]- 使用指定缓冲区大小和变量名包装函数体进行 WebSocket 流处理。#[ws_from_stream(variable_name, buffer_size)]- 使用指定变量名和缓冲区大小(顺序相反)包装函数体进行 WebSocket 流处理。
响应头宏
响应体宏
路由宏
#[route("path")]- 为给定路径注册路由处理器,使用默认服务器(前提:需要#[hyperlane(server: Server)]宏)
辅助提示
- 请求相关宏(数据提取)使用
get操作 - 从请求中检索/查询数据 - 响应相关宏(数据设置)使用
set操作 - 分配/配置响应数据 - 钩子宏 对于支持
order参数的钩子相关宏,如果未指定order,则钩子优先级高于指定order的钩子(仅适用于#[request_middleware]、#[response_middleware]、#[panic_hook]等宏) - 多参数支持 大多数数据提取宏支持单次调用中的多个参数(例如
#[request_body(var1, var2)]、#[request_query("k1" => v1, "k2" => v2)])。这减少了宏重复并提高了代码可读性。
最佳实践警告
- 请求相关宏大多是查询函数,而响应相关宏大多是赋值函数。
- 使用
prologue_hooks或epilogue_hooks宏时,不建议将它们与其他宏(如#[get]、#[post]、#[http]等)组合在同一个函数上。这些宏应放在钩子函数本身中。如果您不清楚宏是如何展开的,组合它们可能导致有问题的代码行为。
示例用法
use hyperlane::*;
use hyperlane_macros::*;
use serde::{Deserialize, Serialize};
const STEP: &str = "step";
const TEST_ATTRIBUTE_KEY: &str = "test_attribute_key";
const CUSTOM_STATUS_CODE: i32 = 200;
const CUSTOM_REASON: &str = "Accepted";
const CUSTOM_HEADER_NAME: &str = "X-Custom-Header";
const CUSTOM_HEADER_VALUE: &str = "custom-value";
const RESPONSE_DATA: &str = "{\"status\": \"success\"}";
#[derive(Debug, Serialize, Deserialize, Clone)]
struct TestData {
name: String,
age: u32,
}
#[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) {}
}
#[request_middleware]
struct RequestMiddleware;
impl ServerHook for RequestMiddleware {
async fn new(_ctx: &Context) -> Self {
Self
}
#[epilogue_macros(
response_status_code(200),
response_version(HttpVersion::HTTP1_1),
response_header(SERVER => HYPERLANE),
response_header(CONNECTION => KEEP_ALIVE),
response_header(CONTENT_TYPE => TEXT_PLAIN),
response_header(ACCESS_CONTROL_ALLOW_ORIGIN => WILDCARD_ANY),
response_header(STEP => "request_middleware"),
)]
async fn handle(self, ctx: &Context) {}
}
#[request_middleware(1)]
struct UpgradeHook;
impl ServerHook for UpgradeHook {
async fn new(_ctx: &Context) -> Self {
Self
}
#[epilogue_macros(
ws,
response_body(&vec![]),
response_status_code(101),
response_header(UPGRADE => WEBSOCKET),
response_header(CONNECTION => UPGRADE),
response_header(SEC_WEBSOCKET_ACCEPT => &WebSocketFrame::generate_accept_key(ctx.try_get_request_header_back(SEC_WEBSOCKET_KEY).await.unwrap())),
response_header(STEP => "upgrade_hook"),
send
)]
async fn handle(self, ctx: &Context) {}
}
#[request_middleware(2)]
struct ConnectedHook;
impl ServerHook for ConnectedHook {
async fn new(_ctx: &Context) -> Self {
Self
}
#[response_status_code(200)]
#[response_header(SERVER => HYPERLANE)]
#[response_version(HttpVersion::HTTP1_1)]
#[response_header(ACCESS_CONTROL_ALLOW_ORIGIN => WILDCARD_ANY)]
#[response_header(STEP => "connected_hook")]
async fn handle(self, ctx: &Context) {}
}
#[response_middleware]
struct ResponseMiddleware1;
impl ServerHook for ResponseMiddleware1 {
async fn new(_ctx: &Context) -> Self {
Self
}
#[response_header(STEP => "response_middleware_1")]
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()),
response_header(STEP => "response_middleware_2")
)]
#[epilogue_macros(send, flush)]
async fn handle(self, ctx: &Context) {}
}
#[response_middleware("3")]
struct ResponseMiddleware3;
impl ServerHook for ResponseMiddleware3 {
async fn new(_ctx: &Context) -> Self {
Self
}
#[prologue_macros(
ws,
response_header(STEP => "response_middleware_3")
)]
#[epilogue_macros(send_body, flush)]
async fn handle(self, ctx: &Context) {}
}
struct PrologueHooks;
impl ServerHook for PrologueHooks {
async fn new(_ctx: &Context) -> Self {
Self
}
#[get]
#[http]
async fn handle(self, _ctx: &Context) {}
}
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 prologue_hooks_fn(ctx: Context) {
let hook = PrologueHooks::new(&ctx).await;
hook.handle(&ctx).await;
}
async fn epilogue_hooks_fn(ctx: Context) {
let hook = EpilogueHooks::new(&ctx).await;
hook.handle(&ctx).await;
}
#[route("/response")]
struct Response;
impl ServerHook for Response {
async fn new(_ctx: &Context) -> Self {
Self
}
#[response_body(&RESPONSE_DATA)]
#[response_reason_phrase(CUSTOM_REASON)]
#[response_status_code(CUSTOM_STATUS_CODE)]
#[response_header(CUSTOM_HEADER_NAME => CUSTOM_HEADER_VALUE)]
async fn handle(self, ctx: &Context) {}
}
#[route("/connect")]
struct Connect;
impl ServerHook for Connect {
async fn new(_ctx: &Context) -> Self {
Self
}
#[prologue_macros(connect, response_body("connect"))]
async fn handle(self, ctx: &Context) {}
}
#[route("/delete")]
struct Delete;
impl ServerHook for Delete {
async fn new(_ctx: &Context) -> Self {
Self
}
#[prologue_macros(delete, response_body("delete"))]
async fn handle(self, ctx: &Context) {}
}
#[route("/head")]
struct Head;
impl ServerHook for Head {
async fn new(_ctx: &Context) -> Self {
Self
}
#[prologue_macros(head, response_body("head"))]
async fn handle(self, ctx: &Context) {}
}
#[route("/options")]
struct Options;
impl ServerHook for Options {
async fn new(_ctx: &Context) -> Self {
Self
}
#[prologue_macros(options, response_body("options"))]
async fn handle(self, ctx: &Context) {}
}
#[route("/patch")]
struct Patch;
impl ServerHook for Patch {
async fn new(_ctx: &Context) -> Self {
Self
}
#[prologue_macros(patch, response_body("patch"))]
async fn handle(self, ctx: &Context) {}
}
#[route("/put")]
struct Put;
impl ServerHook for Put {
async fn new(_ctx: &Context) -> Self {
Self
}
#[prologue_macros(put, response_body("put"))]
async fn handle(self, ctx: &Context) {}
}
#[route("/trace")]
struct Trace;
impl ServerHook for Trace {
async fn new(_ctx: &Context) -> Self {
Self
}
#[prologue_macros(trace, response_body("trace"))]
async fn handle(self, ctx: &Context) {}
}
#[route("/h2c")]
struct H2c;
impl ServerHook for H2c {
async fn new(_ctx: &Context) -> Self {
Self
}
#[prologue_macros(h2c, response_body("h2c"))]
async fn handle(self, ctx: &Context) {}
}
#[route("/http")]
struct HttpOnly;
impl ServerHook for HttpOnly {
async fn new(_ctx: &Context) -> Self {
Self
}
#[prologue_macros(http, response_body("http"))]
async fn handle(self, ctx: &Context) {}
}
#[route("/http0_9")]
struct Http09;
impl ServerHook for Http09 {
async fn new(_ctx: &Context) -> Self {
Self
}
#[prologue_macros(http0_9, response_body("http0_9"))]
async fn handle(self, ctx: &Context) {}
}
#[route("/http1_0")]
struct Http10;
impl ServerHook for Http10 {
async fn new(_ctx: &Context) -> Self {
Self
}
#[prologue_macros(http1_0, response_body("http1_0"))]
async fn handle(self, ctx: &Context) {}
}
#[route("/http1_1")]
struct Http11;
impl ServerHook for Http11 {
async fn new(_ctx: &Context) -> Self {
Self
}
#[prologue_macros(http1_1, response_body("http1_1"))]
async fn handle(self, ctx: &Context) {}
}
#[route("/http2")]
struct Http2;
impl ServerHook for Http2 {
async fn new(_ctx: &Context) -> Self {
Self
}
#[prologue_macros(http2, response_body("http2"))]
async fn handle(self, ctx: &Context) {}
}
#[route("/http3")]
struct Http3;
impl ServerHook for Http3 {
async fn new(_ctx: &Context) -> Self {
Self
}
#[prologue_macros(http3, response_body("http3"))]
async fn handle(self, ctx: &Context) {}
}
#[route("/tls")]
struct Tls;
impl ServerHook for Tls {
async fn new(_ctx: &Context) -> Self {
Self
}
#[prologue_macros(tls, response_body("tls"))]
async fn handle(self, ctx: &Context) {}
}
#[route("/http1_1_or_higher")]
struct Http11OrHigher;
impl ServerHook for Http11OrHigher {
async fn new(_ctx: &Context) -> Self {
Self
}
#[prologue_macros(http1_1_or_higher, response_body("http1_1_or_higher"))]
async fn handle(self, ctx: &Context) {}
}
#[route("/unknown_method")]
struct UnknownMethod;
impl ServerHook for UnknownMethod {
async fn new(_ctx: &Context) -> Self {
Self
}
#[prologue_macros(
clear_response_headers,
filter(ctx.get_request().await.is_unknown_method()),
response_body("unknown_method")
)]
async fn handle(self, ctx: &Context) {}
}
#[route("/get")]
struct Get;
impl ServerHook for Get {
async fn new(_ctx: &Context) -> Self {
Self
}
#[prologue_macros(ws, get, response_body("get"), send_body_once)]
async fn handle(self, ctx: &Context) {}
}
#[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) {}
}
#[route("/ws1")]
struct Websocket1;
impl ServerHook for Websocket1 {
async fn new(_ctx: &Context) -> Self {
Self
}
#[ws]
#[ws_from_stream]
async fn handle(self, ctx: &Context) {
let body: RequestBody = ctx.get_request_body().await;
let body_list: Vec<ResponseBody> = WebSocketFrame::create_frame_list(&body);
ctx.send_body_list_with_data(&body_list).await.unwrap();
}
}
#[route("/ws2")]
struct Websocket2;
impl ServerHook for Websocket2 {
async fn new(_ctx: &Context) -> Self {
Self
}
#[ws]
#[ws_from_stream(request)]
async fn handle(self, ctx: &Context) {
let body: &RequestBody = request.get_body();
let body_list: Vec<ResponseBody> = WebSocketFrame::create_frame_list(body);
ctx.send_body_list_with_data(&body_list).await.unwrap();
}
}
#[route("/ws3")]
struct Websocket3;
impl ServerHook for Websocket3 {
async fn new(_ctx: &Context) -> Self {
Self
}
#[ws]
#[ws_from_stream(1024, request)]
async fn handle(self, ctx: &Context) {
let body: &RequestBody = request.get_body();
let body_list: Vec<ResponseBody> = WebSocketFrame::create_frame_list(body);
ctx.send_body_list_with_data(&body_list).await.unwrap();
}
}
#[route("/ws4")]
struct Websocket4;
impl ServerHook for Websocket4 {
async fn new(_ctx: &Context) -> Self {
Self
}
#[ws]
#[ws_from_stream(request, 1024)]
async fn handle(self, ctx: &Context) {
let body: &RequestBody = request.get_body();
let body_list: Vec<ResponseBody> = WebSocketFrame::create_frame_list(body);
ctx.send_body_list_with_data(&body_list).await.unwrap();
}
}
#[route("/ws5")]
struct Websocket5;
impl ServerHook for Websocket5 {
async fn new(_ctx: &Context) -> Self {
Self
}
#[ws]
#[ws_from_stream(1024)]
async fn handle(self, ctx: &Context) {
let body: RequestBody = ctx.get_request_body().await;
let body_list: Vec<ResponseBody> = WebSocketFrame::create_frame_list(&body);
ctx.send_body_list_with_data(&body_list).await.unwrap();
}
}
#[route("/hook")]
struct Hook;
impl ServerHook for Hook {
async fn new(_ctx: &Context) -> Self {
Self
}
#[prologue_hooks(prologue_hooks_fn)]
#[epilogue_hooks(epilogue_hooks_fn)]
#[response_body("Testing hook macro")]
async fn handle(self, ctx: &Context) {}
}
#[route("/get_post")]
struct GetPost;
impl ServerHook for GetPost {
async fn new(_ctx: &Context) -> Self {
Self
}
#[closed]
#[prologue_macros(
http,
methods(get, post),
response_body("get_post"),
response_status_code(200),
response_reason_phrase("OK")
)]
async fn handle(self, ctx: &Context) {}
}
#[route("/attributes")]
struct Attributes;
impl ServerHook for Attributes {
async fn new(_ctx: &Context) -> Self {
Self
}
#[response_body(&format!("request attributes: {request_attributes:?}"))]
#[attributes(request_attributes)]
async fn handle(self, ctx: &Context) {}
}
#[route("/route_params/:test")]
struct RouteParams;
impl ServerHook for RouteParams {
async fn new(_ctx: &Context) -> Self {
Self
}
#[response_body(&format!("request route params: {request_route_params:?}"))]
#[route_params(request_route_params)]
async fn handle(self, ctx: &Context) {}
}
#[route("/route_param/:test")]
struct RouteParam;
impl ServerHook for RouteParam {
async fn new(_ctx: &Context) -> Self {
Self
}
#[response_body(&format!("route param: {request_route_param:?} {request_route_param1:?} {request_route_param2:?}"))]
#[route_param("test" => request_route_param)]
#[route_param("test1" => request_route_param1, "test2" => request_route_param2)]
async fn handle(self, ctx: &Context) {}
}
#[route("/host")]
struct Host;
impl ServerHook for Host {
async fn new(_ctx: &Context) -> Self {
Self
}
#[host("localhost")]
#[epilogue_macros(
response_body("host string literal: localhost"),
send,
http_from_stream
)]
#[prologue_macros(response_body("host string literal: localhost"), send)]
async fn handle(self, ctx: &Context) {}
}
#[route("/request_query")]
struct RequestQuery;
impl ServerHook for RequestQuery {
async fn new(_ctx: &Context) -> Self {
Self
}
#[epilogue_macros(
request_query("test" => request_query_option),
response_body(&format!("request query: {request_query_option:?}")),
send,
http_from_stream(1024)
)]
#[prologue_macros(
request_query("test" => request_query_option),
response_body(&format!("request query: {request_query_option:?}")),
send
)]
async fn handle(self, ctx: &Context) {}
}
#[route("/request_header")]
struct RequestHeader;
impl ServerHook for RequestHeader {
async fn new(_ctx: &Context) -> Self {
Self
}
#[epilogue_macros(
request_header(HOST => request_header_option),
response_body(&format!("request header: {request_header_option:?}")),
send,
http_from_stream(_request)
)]
#[prologue_macros(
request_header(HOST => request_header_option),
response_body(&format!("request header: {request_header_option:?}")),
send
)]
async fn handle(self, ctx: &Context) {}
}
#[route("/request_querys")]
struct RequestQuerys;
impl ServerHook for RequestQuerys {
async fn new(_ctx: &Context) -> Self {
Self
}
#[epilogue_macros(
request_querys(request_querys),
response_body(&format!("request querys: {request_querys:?}")),
send,
http_from_stream(1024, _request)
)]
#[prologue_macros(
request_querys(request_querys),
response_body(&format!("request querys: {request_querys:?}")),
send
)]
async fn handle(self, ctx: &Context) {}
}
#[route("/request_headers")]
struct RequestHeaders;
impl ServerHook for RequestHeaders {
async fn new(_ctx: &Context) -> Self {
Self
}
#[epilogue_macros(
request_headers(request_headers),
response_body(&format!("request headers: {request_headers:?}")),
send,
http_from_stream(_request, 1024)
)]
#[prologue_macros(
request_headers(request_headers),
response_body(&format!("request headers: {request_headers:?}")),
send
)]
async fn handle(self, ctx: &Context) {}
}
#[route("/request_body")]
struct RequestBodyRoute;
impl ServerHook for RequestBodyRoute {
async fn new(_ctx: &Context) -> Self {
Self
}
#[response_body(&format!("raw body: {raw_body:?}"))]
#[request_body(raw_body)]
async fn handle(self, ctx: &Context) {}
}
#[route("/reject_host")]
struct RejectHost;
impl ServerHook for RejectHost {
async fn new(_ctx: &Context) -> Self {
Self
}
#[prologue_macros(
reject_host("filter.localhost"),
response_body("host filter string literal")
)]
async fn handle(self, ctx: &Context) {}
}
#[route("/attribute")]
struct Attribute;
impl ServerHook for Attribute {
async fn new(_ctx: &Context) -> Self {
Self
}
#[response_body(&format!("request attribute: {request_attribute_option:?}"))]
#[attribute(TEST_ATTRIBUTE_KEY => request_attribute_option: TestData)]
async fn handle(self, ctx: &Context) {}
}
#[route("/request_body_json")]
struct RequestBodyJson;
impl ServerHook for RequestBodyJson {
async fn new(_ctx: &Context) -> Self {
Self
}
#[response_body(&format!("request data: {request_data_result:?}"))]
#[request_body_json(request_data_result: TestData)]
async fn handle(self, ctx: &Context) {}
}
#[route("/referer")]
struct Referer;
impl ServerHook for Referer {
async fn new(_ctx: &Context) -> Self {
Self
}
#[prologue_macros(
referer("http://localhost"),
response_body("referer string literal: http://localhost")
)]
async fn handle(self, ctx: &Context) {}
}
#[route("/reject_referer")]
struct RejectReferer;
impl ServerHook for RejectReferer {
async fn new(_ctx: &Context) -> Self {
Self
}
#[prologue_macros(
reject_referer("http://localhost"),
response_body("referer filter string literal")
)]
async fn handle(self, ctx: &Context) {}
}
#[route("/cookies")]
struct Cookies;
impl ServerHook for Cookies {
async fn new(_ctx: &Context) -> Self {
Self
}
#[response_body(&format!("All cookies: {cookie_value:?}"))]
#[request_cookies(cookie_value)]
async fn handle(self, ctx: &Context) {}
}
#[route("/cookie")]
struct Cookie;
impl ServerHook for Cookie {
async fn new(_ctx: &Context) -> Self {
Self
}
#[response_body(&format!("Session cookie: {session_cookie_opt:?}"))]
#[request_cookie("test" => session_cookie_opt)]
async fn handle(self, ctx: &Context) {}
}
#[route("/request_version")]
struct RequestVersionTest;
impl ServerHook for RequestVersionTest {
async fn new(_ctx: &Context) -> Self {
Self
}
#[response_body(&format!("HTTP Version: {http_version}"))]
#[request_version(http_version)]
async fn handle(self, ctx: &Context) {}
}
#[route("/request_path")]
struct RequestPathTest;
impl ServerHook for RequestPathTest {
async fn new(_ctx: &Context) -> Self {
Self
}
#[response_body(&format!("Request Path: {request_path}"))]
#[request_path(request_path)]
async fn handle(self, ctx: &Context) {}
}
#[route("/response_header")]
struct ResponseHeaderTest;
impl ServerHook for ResponseHeaderTest {
async fn new(_ctx: &Context) -> Self {
Self
}
#[response_body("Testing header set and replace operations")]
#[response_header("X-Add-Header", "add-value")]
#[response_header("X-Set-Header" => "set-value")]
async fn handle(self, ctx: &Context) {}
}
#[route("/literals")]
struct Literals;
impl ServerHook for Literals {
async fn new(_ctx: &Context) -> Self {
Self
}
#[response_status_code(201)]
#[response_header(CONTENT_TYPE => APPLICATION_JSON)]
#[response_body("{\"message\": \"Resource created\"}")]
#[response_reason_phrase(HttpStatus::Created.to_string())]
async fn handle(self, ctx: &Context) {}
}
#[route("/inject/response_body")]
struct InjectResponseBody;
impl ServerHook for InjectResponseBody {
async fn new(_ctx: &Context) -> Self {
Self
}
async fn handle(self, ctx: &Context) {
self.response_body_with_ref_self(ctx).await;
}
}
impl InjectResponseBody {
#[response_body("response body with ref self")]
async fn response_body_with_ref_self(&self, ctx: &Context) {}
}
#[route("/inject/post_method")]
struct InjectPostMethod;
impl ServerHook for InjectPostMethod {
async fn new(_ctx: &Context) -> Self {
Self
}
async fn handle(self, ctx: &Context) {
self.post_method_with_ref_self(ctx).await;
}
}
impl InjectPostMethod {
#[prologue_macros(post, response_body("post method with ref self"))]
async fn post_method_with_ref_self(&self, ctx: &Context) {}
}
#[route("/inject/send_flush")]
struct InjectSendFlush;
impl ServerHook for InjectSendFlush {
async fn new(_ctx: &Context) -> Self {
Self
}
async fn handle(self, ctx: &Context) {
self.send_and_flush_with_ref_self(ctx).await;
}
}
impl InjectSendFlush {
#[epilogue_macros(send, flush)]
async fn send_and_flush_with_ref_self(&self, ctx: &Context) {}
}
#[route("/inject/request_body")]
struct InjectRequestBody;
impl ServerHook for InjectRequestBody {
async fn new(_ctx: &Context) -> Self {
Self
}
async fn handle(self, ctx: &Context) {
self.extract_request_body_with_ref_self(ctx).await;
}
}
impl InjectRequestBody {
#[request_body(_raw_body)]
async fn extract_request_body_with_ref_self(&self, _ctx: &Context) {}
}
#[route("/inject/multiple_methods")]
struct InjectMultipleMethods;
impl ServerHook for InjectMultipleMethods {
async fn new(_ctx: &Context) -> Self {
Self
}
async fn handle(self, ctx: &Context) {
self.multiple_methods_with_ref_self(ctx).await;
}
}
impl InjectMultipleMethods {
#[methods(get, post)]
async fn multiple_methods_with_ref_self(&self, ctx: &Context) {}
}
#[route("/inject/http_stream")]
struct InjectHttpStream;
impl ServerHook for InjectHttpStream {
async fn new(_ctx: &Context) -> Self {
Self
}
async fn handle(self, ctx: &Context) {
self.http_stream_handler_with_ref_self(ctx).await;
}
}
impl InjectHttpStream {
#[http_from_stream(1024, _request)]
async fn http_stream_handler_with_ref_self(&self, _ctx: &Context) {}
}
#[route("/inject/ws_stream")]
struct InjectWsStream;
impl ServerHook for InjectWsStream {
async fn new(_ctx: &Context) -> Self {
Self
}
async fn handle(self, ctx: &Context) {
self.websocket_stream_handler_with_ref_self(ctx).await;
}
}
impl InjectWsStream {
#[ws_from_stream(_request)]
async fn websocket_stream_handler_with_ref_self(&self, _ctx: &Context) {}
}
#[route("/inject/complex_post")]
struct InjectComplexPost;
impl ServerHook for InjectComplexPost {
async fn new(_ctx: &Context) -> Self {
Self
}
async fn handle(self, ctx: &Context) {
self.complex_post_handler_with_ref_self(ctx).await;
}
}
impl InjectComplexPost {
#[prologue_macros(
post,
http,
request_body(raw_body),
response_status_code(201),
response_header(CONTENT_TYPE => APPLICATION_JSON),
response_body(&format!("Received: {raw_body:?}"))
)]
#[epilogue_macros(send, flush)]
async fn complex_post_handler_with_ref_self(&self, ctx: &Context) {}
}
impl InjectComplexPost {
#[post]
async fn test_with_bool_param(_a: bool, ctx: &Context) {}
#[get]
async fn test_with_multiple_params(_a: bool, ctx: &Context, _b: i32) {}
}
#[response_body("standalone response body")]
async fn standalone_response_body_handler(ctx: &Context) {}
#[prologue_macros(get, response_body("standalone get handler"))]
async fn standalone_get_handler(ctx: &Context) {}
#[epilogue_macros(send, flush)]
async fn standalone_send_and_flush_handler(ctx: &Context) {}
#[request_body(_raw_body)]
async fn standalone_request_body_extractor(ctx: &Context) {}
#[methods(get, post)]
async fn standalone_multiple_methods_handler(ctx: &Context) {}
#[http_from_stream]
async fn standalone_http_stream_handler(ctx: &Context) {}
#[ws_from_stream]
async fn standalone_websocket_stream_handler(ctx: &Context) {}
#[prologue_macros(
get,
http,
response_status_code(200),
response_header(CONTENT_TYPE => TEXT_PLAIN),
response_body("standalone complex handler")
)]
#[epilogue_macros(send, flush)]
async fn standalone_complex_get_handler(ctx: &Context) {}
#[get]
async fn standalone_get_handler_with_param(_a: bool, ctx: &Context) {}
#[request_body(body1, body2, body3)]
async fn test_multi_request_body(ctx: &Context) {
println!("body1: {:?}, body2: {:?}, body3: {:?}", body1, body2, body3);
}
#[route("/test_multi_request_body_json")]
#[derive(Debug, serde::Deserialize)]
struct User {
name: String,
}
impl ServerHook for User {
async fn new(_ctx: &Context) -> Self {
Self {
name: String::from("test"),
}
}
#[prologue_macros(
request_body_json(user1: User, user2: User),
response_body(format!(
"user1: {:?}, user2: {:?}",
user1.unwrap().name,
user2.unwrap().name
)),
send
)]
async fn handle(self, ctx: &Context) {}
}
#[attribute("key1" => attr1: String, "key2" => attr2: i32)]
async fn test_multi_attribute(ctx: &Context) {
println!("attr1: {:?}, attr2: {:?}", attr1, attr2);
}
#[attributes(attrs1, attrs2)]
async fn test_multi_attributes(ctx: &Context) {
println!("attrs1: {:?}, attrs2: {:?}", attrs1, attrs2);
}
#[route_params(params1, params2)]
async fn test_multi_route_params(ctx: &Context) {
println!("params1: {:?}, params2: {:?}", params1, params2);
}
#[request_querys(querys1, querys2)]
async fn test_multi_request_querys(ctx: &Context) {
println!("querys1: {:?}, querys2: {:?}", querys1, querys2);
}
#[request_headers(headers1, headers2)]
async fn test_multi_request_headers(ctx: &Context) {
println!("headers1: {:?}, headers2: {:?}", headers1, headers2);
}
#[request_cookies(cookies1, cookies2)]
async fn test_multi_request_cookies(ctx: &Context) {
println!("cookies1: {:?}, cookies2: {:?}", cookies1, cookies2);
}
#[request_version(version1, version2)]
async fn test_multi_request_version(ctx: &Context) {
println!("version1: {:?}, version2: {:?}", version1, version2);
}
#[request_path(path1, path2)]
async fn test_multi_request_path(ctx: &Context) {
println!("path1: {:?}, path2: {:?}", path1, path2);
}
#[host("localhost", "127.0.0.1")]
async fn test_multi_host(ctx: &Context) {
println!("Host check passed");
}
#[reject_host("badhost.com", "spam.com")]
async fn test_multi_reject_host(ctx: &Context) {
println!("Reject host check passed");
}
#[referer("http://localhost", "http://127.0.0.1")]
async fn test_multi_referer(ctx: &Context) {
println!("Referer check passed");
}
#[reject_referer("http://badsite.com", "http://spam.com")]
async fn test_multi_reject_referer(ctx: &Context) {
println!("Reject referer check passed");
}
#[hyperlane(server1: Server, server2: Server)]
async fn test_multi_hyperlane() {
println!("server1 and server2 initialized");
}
#[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;
}许可证
该项目使用 MIT 许可证。详情请参阅 LICENSE 文件。
贡献
欢迎贡献!请提交问题或拉取请求。
联系方式
如有任何问题,请联系作者 [email protected]。
加载中...