hyperlane-macros
2025年10月24日大约 14 分钟hyperlane-macros
一个用于构建具有增强功能的 HTTP 服务器的综合性过程宏集合。该 crate 提供了属性宏,可简化 HTTP 请求处理、协议验证、响应管理和请求数据提取。
安装
要使用此 crate,您可以运行 cmd:
cargo add hyperlane-macros可用宏
Hyperlane 宏
#[hyperlane(server: Server)]- 创建一个具有指定变量名和类型的新Server实例,并自动注册 crate 中定义的其他钩子和路由。#[hyperlane(config: ServerConfig)]- 创建一个具有指定变量名和类型的新ServerConfig实例。
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_json(variable_name: type)]- 将请求体解析为 JSON 并放入指定变量和类型中
属性宏
#[attribute(key => variable_name: type)]- 按键提取特定属性到类型化变量中
属性集合宏
#[attributes(variable_name)]- 获取所有属性作为 HashMap 以进行综合属性访问
路由参数宏
#[route_param(key => variable_name)]- 按键提取特定路由参数到变量中
路由参数集合宏
#[route_params(variable_name)]- 获取所有路由参数作为集合
请求查询宏
#[request_query(key => variable_name)]- 从 URL 查询字符串中按键提取特定查询参数
请求查询集合宏
#[request_querys(variable_name)]- 获取所有查询参数作为集合
请求头宏
#[request_header(key => variable_name)]- 从请求中按名称提取特定 HTTP 头
请求头集合宏
#[request_headers(variable_name)]- 获取所有 HTTP 头作为集合
请求 Cookie 宏
#[request_cookie(key => variable_name)]- 从请求 cookie 头中按键提取特定 cookie 值
请求 Cookie 集合宏
#[request_cookies(variable_name)]- 从 cookie 头中获取所有 cookie 作为原始字符串
请求版本宏
#[request_version(variable_name)]- 将 HTTP 请求版本提取到变量中
请求路径宏
#[request_path(variable_name)]- 将 HTTP 请求路径提取到变量中
主机宏
#[host("hostname")]- 限制函数执行到具有特定主机头值的请求#[reject_host("hostname")]- 拒绝匹配特定主机头值的请求
引用宏
#[referer("url")]- 限制函数执行到具有特定引用头值的请求#[reject_referer("url")]- 拒绝匹配特定引用头值的请求
钩子宏
#[prologue_hooks(function_name)]- 在主处理函数之前执行指定函数#[epilogue_hooks(function_name)]- 在主处理函数之后执行指定函数#[panic_hook]- 在服务器内发生恐慌时执行函数#[prologue_macros(macro1, macro2, ...)]- 在装饰函数之前注入宏列表。#[epilogue_macros(macro1, macro2, ...)]- 在装饰函数之后注入宏列表。
中间件宏
#[request_middleware]- 将函数注册为请求中间件#[request_middleware(order)]- 将函数注册为具有指定顺序的请求中间件#[response_middleware]- 将函数注册为响应中间件#[response_middleware(order)]- 将函数注册为具有指定顺序的响应中间件#[panic_hook]- 将函数注册为恐慌钩子#[panic_hook(order)]- 将函数注册为具有指定顺序的恐慌钩子
流处理宏
#[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]等宏)
最佳实践警告
- 请求相关宏主要是查询函数,而响应相关宏主要是赋值函数。
- 使用
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:?}"))]
#[route_param("test" => request_route_param)]
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) {}
#[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]。
