aex 0.1.4

A web server for rust.
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499

# AEX — Async-first, Executor-based Web/TCP/UDP Framework for Rust

> 一个轻量、可控、忠于 HTTP 本质的 Rust Web 框架

## AEX 是什么?

AEX.rs 是一个轻量级异步 Rust Web 框架

1. 提供直觉的,易用的HTTP路由
2. 提供 简单,直观,正确的中间件机制
3. 原生支持 WebSocket,只需要放到中间件上,就可以实现WebSocket处理
4. 面向真实网络 I/O,而非抽象叠加

> 为 Rust 开发者提供更清晰、更可控的 Web 编程体验


---

## Aex安装与使用

1. 创建项目目录

```bash
cargo new xxx
cd xxx
```

> 将xxx换成自己的项目名称

2. 安装aex

```bash
cargo add aex
```

3. 安装依赖

```bash
cargo add tokio futures futures_util anyhow
```

安装完成后,将下面的`hello world`跑通就可以进行项目的相关开发了。

---

## 最简单的Hello World实现


```rust
#[tokio::main]
async fn main() -> anyhow::Result<()> {
    let addr: SocketAddr = "0.0.0.0:8080".parse()?;
    let mut router = HttpRouter::new(NodeType::Static("root".into()));

    route!(
        router,
        get!(
            "/",
            exe!(|ctx| {
                let meta = &mut ctx.local.get_value::<HttpMetadata>().unwrap();
                body!(meta, "Hello world!");
                true
            })
        )
    );
    HTTPServer::new(addr).http(router).start().await?;
    Ok(())
}
```

---

这段框架代码主要就是三个部分:

1. 支持异步与多线程的主函数框架

```rust
#[tokio::main(flavor = "multi_thread")]
async fn main() -> anyhow::Result<()> {
}
```

2. 路由构建与处理函数编写
3. HTTP服务器的创建与运行

```rust
    let ip = "0.0.0.0";
    let port = 8080;
    let addr: SocketAddr = format!("{}:{}", ip, port).parse()?;
    let server = HTTPServer::new(addr, route);
    server.run().await?;
```

---

1.和3.部分属于固定套路,只要照搬就可以了,我就不再详细讲解。

2.部分的结构是编写HTTP业务逻辑的核心。我们可以详细看一下。

---

```rust
  // 1. 创建静态根(root)节点
  let mut route = Router::new(NodeType::Static("root".into()));
  // 2. 使用route!宏添加路由信息
  route!(
      route,
      // 3. 使用get!宏创建一个只响应http get请求的处理函数
      get!("/", |ctx: &mut HTTPContext| {
        // 闭包函数是Exector对象,是一个传入核心对象HTTPContext的异步闭包处理函数
        // Box::pin().boxed()是套路代码,为实现异步闭包所必须的封装。
          Box::pin(async move {
              // 这里是核心处理逻辑,所有处理都在这里编写
              // 输出影响默认在内部调用,直到你返回false
              ctx.res.body.push("Hello world!".to_string());
              // false = 不继续 middleware,不执行最终handle
              true
          }).boxed()
      })
  );
```

---

上面的代码等 价于:

```rust
    let mut route = Router::new(NodeType::Static("root".into()));
    route.insert(
        "/",
        Some("GET"),
        Arc::new(|ctx: &mut HTTPContext| {
            Box::pin(async move {
                ctx.res.body.push("Hello world!".to_string());
                true
            }).boxed()
        }),
        None // 传入 WebSocket 中间件,这里没有中间件使用None
    );
```

---

## 中间件设计理念

中间件 = Executor 的有序数组

1. 中间件不是“魔法层”

2. 不是隐式嵌套

而是 `显式`、`有序`、`可预测`的`执行链`,可以清晰的反映`HTTP`请求的执行`路径`

```
[ Executor A ] → [ Executor B ] → [ Executor C ]
```

---

## 为什么不用“洋葱模型”?

许多 Rust Web 框架采用了错误的洋葱模型。导致一系列错误的结果:

1. 执行顺序不直观
2. 控制流被隐藏
3. 调试成本高
4. 实际与 HTTP 请求生命周期不匹配

而绝大部分的Rust框架都被污染。

> 这也是我重写一个新框架的主要原因

---

## AEX 的核心目标

1. 让Rust的Web开发更加容易
   一开始使用时,不用对Rust太了解就可以写出基本的Web处理
   不需要学一堆莫名其妙的函数的使用
2. 还原 HTTP 请求的本来面目
   包括:
   1. 请求如何进来
   2. 中间件如何执行
   3. 响应如何写出
      全部 明确、可见、可理解

---

## 开发体验目标

让 Rust Web 编程变得更简单

1. 书写方式友好
2. API 接口直观
3. 行为符合直觉

不需要“框架思维负担”

> 你写的是 Web 逻辑,而不是给框架写扩展

框架是服务于你的业务逻辑的。
框架的任务是拆解Web逻辑,让你的Web逻辑处理起来简单,从而专注于你的业务本身。

---

## 性能

AEX 不是性能优先型框架,而是应用业务优先型框架。

当前性能没有达到顶级性能框架的水平,但是能于应用开发优先的框架,

Aex可以提供不错的早期性能。

随着Aex的成熟,未来会不断的优化,达到顶级的性能水平。

性能优化是所有成熟框架必走的道路,但是设计的错误是无法优化的。

所以早期的策略是优先确保设计是正确的。

---

## 基本设计原则

1. 核心接口保持精简,一致,不变
2. API 不随意增加
3. 执行路径简单明晰
4. 源码结构简单,容易理解,便加参与,扩展

性能优化过程中,这些设计理念与原则不会变化

---

## 适合谁?

AEX 适合什么样的开发者

1. 需要专注于业务开发
2. 希望Web的逻辑与业务逻辑分离
3. 希望快速写出原型Web服务器的

---

## 核心概念

Aex是一个非常简单的框架。它的核心概念就只有三个:

1. Router: 基于Trie树的高性能路由器
2. Executor: 请求处理与中间件都依赖于它
3. HTTPContext: 分请求数据与全局数据,HTTP数据的运输载体

---

## 扩展概念

基于核心概念,扩展出来的几个重要概念

1. Middleware: 一个有序的Exector数组列表,当其中一个返回false时,可以终止后续的Exector执行
2. Handler: 最后一个执行的Exector,也是一个HTTP请求最终处理,并返回的地方
3. WebSocket: 处理WebSocket的基础处理结构,通过WebSocket::to_middleware生成中间件,放到Middleware中
4. Server: 实现基本的Http服务器启动功能,并实现与Router对接

---

## 宏的使用

宏的使用就是将参数进行切分,属于路由描述语言。

比如

```rust
get!("/path", handler, [mw1, mw2])
```

等价于参数列表

```rust
(
"GET",
"/path",
// handler是一个Executor类型,外套一个Arc类型
Arc<Executor>,
// mw1, mw2也都是Executor,组成一个Vec<Arc<Executor>>类型的数组[mw1, mw2]传给route
Some(Vec<Arc<Executor>>)
)
```

---

## 宏的使用结构

```rust
route!(route, xxx!(path, handler[, [mw1, mw2, mw3 ...]]));
```

其中

1. route!就是Router的insert宏
2. xxx!就是接收http的xxx方法在handler进行处理,全部是小写的。包括: `get!`, `post!`, `put!`, `delete!`, `patch!`, `options!`, `head!`, `trace!`, `connect!`
3. all!表示接收所有http方法进行处理,类似于路径为"\*"

---

## 中间件及路由的执行顺序

中间件虽然在参数上位于handler之后,然后它的执行是先开handler的
对于

```rust
route!(route, get!(path, handler, [mw1, mw2, mw3]))
```

它们的执行顺序是:

```rust
mw1 => mw2 => mw3 => handler
```

它在理论上满足HTTP的直线性处理方式(简直Web直线):

```
请求开始 =》数据接收与存储/参数校验 =》 身份校验 =》 数据分析与处理 =》 业务处理 =》 数据发送 =》 请求结束
```

---

## 对WebSocket的支持

随着互联网技术的发展以及对网页端实时交互的强烈需求,浏览器端的实际传输已经是刚需求。
这也要求服务器端对WebSocket的很好的支持。
这也是Aex天然支持WebSocket的原因。

由于WebSocket的处理机制是基于HTTP协议的。
所以我们没有必要脱离HTTP框架。
因为Aex的中间件是正确的机制,所以WebSocket的基本处理放在中间件处理即可

---

## WebSocket,以一种特殊的中间件的方式去实现

在Aex框架内

1. WebSocket的基本协议处理,已经被Aex消化
2. 不用当成是“特殊协议”
3. 当成是特殊的(升级的)中间件即可

---

## WebSocket,为什么应该是中间件

1. 共享http头信息
   很多框架因为没有共享http中间件,WebSocket无法共享Http的相关信息,成为典型的设计缺陷
2. 共享路由信息
   可以将WebSocket的升级路径与它的HTTP路径共享,逻辑更加集中
3. 多路WebSocket处理
   不同的路径下可以有不同的WebSocket处理逻辑,更好的HTTP协作
4. http头或者前期数据处理
   WebSocket也需要很多前置中间件处理一些需要的http头信息或者前置数据

---

## WebSocket的支持

WebSocket中间件目前主要关心

1. on_text : 处理文本交互
2. on_binary: 处理二进制数据交互

这两种主流数据的交互。

实现WebSocket功能的过程很简单,主要分以下四步:

---

### 1. 编写WebSocket的

on_text
on_binary
处理函数。

要注意类型分别为`TextHandler`和`BinaryHandler`时的闭包参数类型的不同。

#### 1. `TextHandler`类型闭包参数是`String`类型

```rust
    let text_handler: TextHandler = Arc::new(|ws: &WebSocket, ctx: &mut HTTPContext, text: String| {
        (
            async move {
                // processing here
                true
            }
        ).boxed()
    });
```

---

#### 2. `BinaryHandler`类型闭包参数是`Vec<u8>`类型

```rust
    let binary_handler: BinaryHandler = Arc::new(
        |ws: &WebSocket, ctx: &mut HTTPContext, data: Vec<u8>| {
            (
                async move {
                    // processing here
                    true
                }
            ).boxed()
        }
    );
```

---

### 2. 将处理函数放到WebSocket对象上

```rust
    let ws = WebSocket {
        on_binary: Some(binary_handler),
        on_text: Some(text_handler),
    };
```

---

### 3. 生成Executor中间件

```rust
    let ws_mw = WebSocket::to_middleware(ws);
```

### 4. 生成带有路径与http方法的宏处理参数

```rust
    let ws_params = get!(
        "/",
        |ctx|
            (
                async move {
                    true
                }
            ).boxed(),
        [ws_mw]
    );
```

---

### 5. 插入到路由的中间件中

```rust
let mut route = Router::new(NodeType::Static("root".into()));
route!(route, ws_params);
```

### 6. 挂载到服务器上

```rust
    let ip = "0.0.0.0";
    let port = 8080;
    let addr: SocketAddr = format!("{}:{}", ip, port).parse()?;
    let server = HTTPServer::new(addr, route);

    server.run().await?;
```

> 外部的main结构保持不变

---

## 为什么选择Aex?

### Aex vs Axum vs Actix

| 维度     | AEX                        | Axum                              | Actix                 |
| -------- | -------------------------- | --------------------------------- | --------------------- |
| 请求模型 | **显式 Executor 顺序执行** | Tower 洋葱模型                    | Actor + Service       |
| 抽象层级 | **极低,贴近 HTTP**        | 高(Service / Layer / Extractor) | 高(Actor / Context) |
| 控制流   | **线性、可预测**           | 隐式嵌套                          | 消息驱动              |
| 中间件   | `Vec<Executor>`            | Layer Stack                       | Middleware / Actor    |

---

| 维度       | AEX                    | Axum            | Actix             |
| ---------- | ---------------------- | --------------- | ----------------- |
| WebSocket  | **HTTP → WS 同一 ctx** | 分离            | 分离              |
| 学习成本   | ****                 |||
| 调试难度   | ****                 | 中偏高          ||
| 可读性     | **顺序即逻辑**         | 需 mental model | 需 actor 思维     |
| 性能上限   | 高(未完全释放)       | 已优化          | 已优化            |
| 架构自由度 | **极高**               | 受 Tower 约束   | 受 Actor 模型约束 |

---

## AI比较总结

- **AEX**:把 Rust Web 框架拉回工程现实,执行顺序可预测,HTTPContext 明确,WebSocket 自然升级,学习成本低。
- **Axum**:Tower 洋葱模型,抽象层多,调试时需要 mental model。
- **Actix**:Actor + Service,消息驱动,高度抽象,学习成本高。