befly 3.10.18 → 3.10.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +83 -307
- package/dist/befly.config.d.ts +7 -0
- package/{befly.config.ts → dist/befly.config.js} +10 -33
- package/dist/checks/checkApi.d.ts +1 -0
- package/{checks/checkApi.ts → dist/checks/checkApi.js} +11 -28
- package/dist/checks/checkHook.d.ts +1 -0
- package/{checks/checkHook.ts → dist/checks/checkHook.js} +11 -20
- package/dist/checks/checkMenu.d.ts +7 -0
- package/{checks/checkMenu.ts → dist/checks/checkMenu.js} +18 -53
- package/dist/checks/checkPlugin.d.ts +1 -0
- package/{checks/checkPlugin.ts → dist/checks/checkPlugin.js} +11 -20
- package/dist/checks/checkTable.d.ts +6 -0
- package/{checks/checkTable.ts → dist/checks/checkTable.js} +17 -41
- package/dist/configs/presetFields.d.ts +4 -0
- package/{configs/presetFields.ts → dist/configs/presetFields.js} +1 -1
- package/dist/configs/presetRegexp.d.ts +145 -0
- package/{utils/regex.ts → dist/configs/presetRegexp.js} +8 -31
- package/dist/hooks/auth.d.ts +5 -0
- package/{hooks/auth.ts → dist/hooks/auth.js} +6 -10
- package/dist/hooks/cors.d.ts +9 -0
- package/{hooks/cors.ts → dist/hooks/cors.js} +3 -13
- package/dist/hooks/parser.d.ts +12 -0
- package/{hooks/parser.ts → dist/hooks/parser.js} +29 -44
- package/dist/hooks/permission.d.ts +12 -0
- package/{hooks/permission.ts → dist/hooks/permission.js} +14 -25
- package/dist/hooks/validator.d.ts +9 -0
- package/{hooks/validator.ts → dist/hooks/validator.js} +7 -14
- package/dist/lib/asyncContext.d.ts +21 -0
- package/dist/lib/asyncContext.js +27 -0
- package/dist/lib/cacheHelper.d.ts +95 -0
- package/{lib/cacheHelper.ts → dist/lib/cacheHelper.js} +45 -105
- package/dist/lib/cacheKeys.d.ts +23 -0
- package/{lib/cacheKeys.ts → dist/lib/cacheKeys.js} +5 -10
- package/dist/lib/cipher.d.ts +153 -0
- package/{lib/cipher.ts → dist/lib/cipher.js} +23 -44
- package/dist/lib/connect.d.ts +91 -0
- package/{lib/connect.ts → dist/lib/connect.js} +47 -88
- package/dist/lib/dbDialect.d.ts +87 -0
- package/{lib/dbDialect.ts → dist/lib/dbDialect.js} +32 -112
- package/dist/lib/dbHelper.d.ts +204 -0
- package/{lib/dbHelper.ts → dist/lib/dbHelper.js} +83 -240
- package/dist/lib/dbUtils.d.ts +68 -0
- package/{lib/dbUtils.ts → dist/lib/dbUtils.js} +51 -125
- package/dist/lib/jwt.d.ts +13 -0
- package/{lib/jwt.ts → dist/lib/jwt.js} +11 -32
- package/dist/lib/logger.d.ts +32 -0
- package/{lib/logger.ts → dist/lib/logger.js} +202 -279
- package/dist/lib/redisHelper.d.ts +185 -0
- package/{lib/redisHelper.ts → dist/lib/redisHelper.js} +97 -141
- package/dist/lib/sqlBuilder.d.ts +160 -0
- package/{lib/sqlBuilder.ts → dist/lib/sqlBuilder.js} +132 -278
- package/dist/lib/sqlCheck.d.ts +23 -0
- package/{lib/sqlCheck.ts → dist/lib/sqlCheck.js} +24 -41
- package/dist/lib/validator.d.ts +45 -0
- package/{lib/validator.ts → dist/lib/validator.js} +44 -61
- package/dist/loader/loadApis.d.ts +12 -0
- package/{loader/loadApis.ts → dist/loader/loadApis.js} +9 -19
- package/dist/loader/loadHooks.d.ts +8 -0
- package/{loader/loadHooks.ts → dist/loader/loadHooks.js} +7 -21
- package/dist/loader/loadPlugins.d.ts +8 -0
- package/{loader/loadPlugins.ts → dist/loader/loadPlugins.js} +10 -22
- package/dist/main.d.ts +26 -0
- package/{main.ts → dist/main.js} +60 -99
- package/dist/paths.d.ts +93 -0
- package/{paths.ts → dist/paths.js} +6 -19
- package/dist/plugins/cache.d.ts +14 -0
- package/{plugins/cache.ts → dist/plugins/cache.js} +5 -12
- package/dist/plugins/cipher.d.ts +10 -0
- package/{plugins/cipher.ts → dist/plugins/cipher.js} +2 -6
- package/dist/plugins/config.d.ts +10 -0
- package/dist/plugins/config.js +6 -0
- package/dist/plugins/db.d.ts +14 -0
- package/{plugins/db.ts → dist/plugins/db.js} +9 -17
- package/dist/plugins/jwt.d.ts +10 -0
- package/dist/plugins/jwt.js +10 -0
- package/dist/plugins/logger.d.ts +28 -0
- package/{plugins/logger.ts → dist/plugins/logger.js} +3 -8
- package/dist/plugins/redis.d.ts +14 -0
- package/{plugins/redis.ts → dist/plugins/redis.js} +7 -12
- package/dist/plugins/tool.d.ts +79 -0
- package/{plugins/tool.ts → dist/plugins/tool.js} +7 -30
- package/dist/router/api.d.ts +14 -0
- package/dist/router/api.js +107 -0
- package/dist/router/static.d.ts +9 -0
- package/{router/static.ts → dist/router/static.js} +20 -34
- package/dist/scripts/ensureDist.d.ts +1 -0
- package/dist/scripts/ensureDist.js +80 -0
- package/dist/sync/syncApi.d.ts +3 -0
- package/{sync/syncApi.ts → dist/sync/syncApi.js} +34 -54
- package/dist/sync/syncCache.d.ts +2 -0
- package/{sync/syncCache.ts → dist/sync/syncCache.js} +1 -6
- package/dist/sync/syncDev.d.ts +6 -0
- package/{sync/syncDev.ts → dist/sync/syncDev.js} +29 -62
- package/dist/sync/syncMenu.d.ts +14 -0
- package/{sync/syncMenu.ts → dist/sync/syncMenu.js} +65 -125
- package/dist/sync/syncTable.d.ts +151 -0
- package/{sync/syncTable.ts → dist/sync/syncTable.js} +171 -378
- package/{types → dist/types}/api.d.ts +8 -47
- package/dist/types/api.js +4 -0
- package/{types → dist/types}/befly.d.ts +31 -222
- package/dist/types/befly.js +4 -0
- package/{types → dist/types}/cache.d.ts +7 -15
- package/dist/types/cache.js +4 -0
- package/dist/types/cipher.d.ts +27 -0
- package/dist/types/cipher.js +7 -0
- package/{types → dist/types}/common.d.ts +8 -33
- package/dist/types/common.js +5 -0
- package/{types → dist/types}/context.d.ts +2 -4
- package/dist/types/context.js +4 -0
- package/{types → dist/types}/crypto.d.ts +0 -3
- package/dist/types/crypto.js +4 -0
- package/dist/types/database.d.ts +138 -0
- package/dist/types/database.js +4 -0
- package/dist/types/hook.d.ts +15 -0
- package/dist/types/hook.js +6 -0
- package/dist/types/jwt.d.ts +75 -0
- package/dist/types/jwt.js +4 -0
- package/dist/types/logger.d.ts +47 -0
- package/dist/types/logger.js +6 -0
- package/dist/types/plugin.d.ts +14 -0
- package/dist/types/plugin.js +6 -0
- package/dist/types/redis.d.ts +71 -0
- package/dist/types/redis.js +4 -0
- package/{types/roleApisCache.ts → dist/types/roleApisCache.d.ts} +0 -2
- package/dist/types/roleApisCache.js +8 -0
- package/dist/types/sync.d.ts +92 -0
- package/dist/types/sync.js +4 -0
- package/dist/types/table.d.ts +34 -0
- package/dist/types/table.js +4 -0
- package/dist/types/validate.d.ts +67 -0
- package/dist/types/validate.js +4 -0
- package/dist/utils/arrayKeysToCamel.d.ts +13 -0
- package/{utils/arrayKeysToCamel.ts → dist/utils/arrayKeysToCamel.js} +5 -5
- package/dist/utils/calcPerfTime.d.ts +4 -0
- package/{utils/calcPerfTime.ts → dist/utils/calcPerfTime.js} +3 -3
- package/dist/utils/configTypes.d.ts +1 -0
- package/dist/utils/configTypes.js +1 -0
- package/dist/utils/convertBigIntFields.d.ts +11 -0
- package/{utils/convertBigIntFields.ts → dist/utils/convertBigIntFields.js} +5 -9
- package/dist/utils/cors.d.ts +8 -0
- package/{utils/cors.ts → dist/utils/cors.js} +1 -3
- package/dist/utils/disableMenusGlob.d.ts +13 -0
- package/{utils/disableMenusGlob.ts → dist/utils/disableMenusGlob.js} +9 -29
- package/dist/utils/fieldClear.d.ts +11 -0
- package/{utils/fieldClear.ts → dist/utils/fieldClear.js} +15 -33
- package/dist/utils/genShortId.d.ts +10 -0
- package/{utils/genShortId.ts → dist/utils/genShortId.js} +1 -1
- package/dist/utils/getClientIp.d.ts +6 -0
- package/{utils/getClientIp.ts → dist/utils/getClientIp.js} +1 -7
- package/dist/utils/importDefault.d.ts +1 -0
- package/dist/utils/importDefault.js +29 -0
- package/dist/utils/isDirentDirectory.d.ts +2 -0
- package/{utils/isDirentDirectory.ts → dist/utils/isDirentDirectory.js} +3 -8
- package/dist/utils/keysToCamel.d.ts +10 -0
- package/{utils/keysToCamel.ts → dist/utils/keysToCamel.js} +4 -5
- package/dist/utils/keysToSnake.d.ts +10 -0
- package/{utils/keysToSnake.ts → dist/utils/keysToSnake.js} +4 -5
- package/dist/utils/loadMenuConfigs.d.ts +5 -0
- package/{utils/loadMenuConfigs.ts → dist/utils/loadMenuConfigs.js} +24 -51
- package/dist/utils/pickFields.d.ts +4 -0
- package/{utils/pickFields.ts → dist/utils/pickFields.js} +2 -5
- package/dist/utils/process.d.ts +24 -0
- package/{utils/process.ts → dist/utils/process.js} +2 -18
- package/dist/utils/processFields.d.ts +4 -0
- package/{utils/processFields.ts → dist/utils/processFields.js} +5 -9
- package/dist/utils/regex.d.ts +145 -0
- package/{configs/presetRegexp.ts → dist/utils/regex.js} +8 -31
- package/dist/utils/response.d.ts +20 -0
- package/{utils/response.ts → dist/utils/response.js} +28 -49
- package/dist/utils/scanAddons.d.ts +17 -0
- package/{utils/scanAddons.ts → dist/utils/scanAddons.js} +6 -40
- package/dist/utils/scanConfig.d.ts +26 -0
- package/{utils/scanConfig.ts → dist/utils/scanConfig.js} +22 -59
- package/dist/utils/scanFiles.d.ts +30 -0
- package/{utils/scanFiles.ts → dist/utils/scanFiles.js} +26 -66
- package/dist/utils/scanSources.d.ts +10 -0
- package/dist/utils/scanSources.js +41 -0
- package/dist/utils/sortModules.d.ts +28 -0
- package/{utils/sortModules.ts → dist/utils/sortModules.js} +25 -65
- package/dist/utils/sqlLog.d.ts +14 -0
- package/{utils/sqlLog.ts → dist/utils/sqlLog.js} +2 -14
- package/package.json +14 -28
- package/.gitignore +0 -0
- package/bunfig.toml +0 -3
- package/docs/README.md +0 -98
- package/docs/api/api.md +0 -1921
- package/docs/guide/examples.md +0 -926
- package/docs/guide/quickstart.md +0 -354
- package/docs/hooks/auth.md +0 -38
- package/docs/hooks/cors.md +0 -28
- package/docs/hooks/hook.md +0 -838
- package/docs/hooks/parser.md +0 -19
- package/docs/hooks/rateLimit.md +0 -47
- package/docs/infra/redis.md +0 -628
- package/docs/plugins/cipher.md +0 -61
- package/docs/plugins/database.md +0 -189
- package/docs/plugins/plugin.md +0 -986
- package/docs/reference/addon.md +0 -510
- package/docs/reference/config.md +0 -573
- package/docs/reference/logger.md +0 -495
- package/docs/reference/sync.md +0 -478
- package/docs/reference/table.md +0 -763
- package/docs/reference/validator.md +0 -620
- package/lib/asyncContext.ts +0 -43
- package/plugins/config.ts +0 -13
- package/plugins/jwt.ts +0 -15
- package/router/api.ts +0 -130
- package/tsconfig.json +0 -8
- package/types/database.d.ts +0 -541
- package/types/hook.d.ts +0 -25
- package/types/jwt.d.ts +0 -118
- package/types/logger.d.ts +0 -65
- package/types/plugin.d.ts +0 -19
- package/types/redis.d.ts +0 -83
- package/types/sync.d.ts +0 -398
- package/types/table.d.ts +0 -216
- package/types/validate.d.ts +0 -69
- package/utils/configTypes.ts +0 -3
- package/utils/importDefault.ts +0 -21
- package/utils/scanSources.ts +0 -64
package/docs/hooks/parser.md
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
# parser Hook - 参数解析
|
|
2
|
-
|
|
3
|
-
> 解析请求体/查询参数,产出统一的 `ctx.body`。
|
|
4
|
-
|
|
5
|
-
## 作用
|
|
6
|
-
|
|
7
|
-
- GET:解析 URL 查询参数
|
|
8
|
-
- POST:解析 JSON(必要时也会支持 XML 等格式,取决于框架实现)
|
|
9
|
-
- 将解析结果写入 `ctx.body`
|
|
10
|
-
|
|
11
|
-
## 行为要点
|
|
12
|
-
|
|
13
|
-
- 解析失败(格式错误)时会提前中断请求,并返回安全的错误信息
|
|
14
|
-
- 该 hook 只负责“把数据变成 ctx.body”,字段校验由后续 `validator` 完成
|
|
15
|
-
|
|
16
|
-
## 常见问题
|
|
17
|
-
|
|
18
|
-
- Q: 为什么 `ctx.body` 里没有某些字段?
|
|
19
|
-
- A: 可能被 fields/required 体系过滤/校验拦截了;请检查 `validator` 与 API 的 `fields/required` 配置。
|
package/docs/hooks/rateLimit.md
DELETED
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
# rateLimit Hook - 全局限流
|
|
2
|
-
|
|
3
|
-
> 按路由与身份维度进行限流(默认启用)。
|
|
4
|
-
|
|
5
|
-
## 默认行为
|
|
6
|
-
|
|
7
|
-
- **默认启用**:`rateLimit.enable = 1`
|
|
8
|
-
- 无规则时:使用兜底配置(默认阈值由框架默认配置提供)
|
|
9
|
-
- `OPTIONS` 请求:不计数也不拦截
|
|
10
|
-
|
|
11
|
-
## 配置
|
|
12
|
-
|
|
13
|
-
```json
|
|
14
|
-
{
|
|
15
|
-
"rateLimit": {
|
|
16
|
-
"enable": 1,
|
|
17
|
-
"rules": [
|
|
18
|
-
{
|
|
19
|
-
"route": "/api/auth/*",
|
|
20
|
-
"limit": 10,
|
|
21
|
-
"window": 60,
|
|
22
|
-
"key": "ip"
|
|
23
|
-
}
|
|
24
|
-
],
|
|
25
|
-
"skipRoutes": ["/api/health"]
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
### route 匹配
|
|
31
|
-
|
|
32
|
-
- 支持精确、前缀、通配(更具体的规则优先)
|
|
33
|
-
|
|
34
|
-
### key 维度
|
|
35
|
-
|
|
36
|
-
- `ip`:按 IP 限流
|
|
37
|
-
- `user`:按用户限流;当缺失 `ctx.user.id` 时会回退为按 IP 计数
|
|
38
|
-
- `ip_user`:IP + 用户组合
|
|
39
|
-
|
|
40
|
-
### skipRoutes
|
|
41
|
-
|
|
42
|
-
命中后直接跳过限流:**不计数也不拦截**。
|
|
43
|
-
|
|
44
|
-
## 存储
|
|
45
|
-
|
|
46
|
-
- 优先使用 Redis(分布式一致)
|
|
47
|
-
- 无 Redis 时降级为进程内计数
|
package/docs/infra/redis.md
DELETED
|
@@ -1,628 +0,0 @@
|
|
|
1
|
-
# Redis 使用指南
|
|
2
|
-
|
|
3
|
-
## 概述
|
|
4
|
-
|
|
5
|
-
Befly 框架使用 Redis 作为缓存层,提供高性能的数据缓存、会话管理和分布式 ID 生成等功能。Redis 插件基于 Bun 内置的 `RedisClient` 实现,封装了常用操作并自动利用 Bun 的 pipeline 特性优化批量操作。
|
|
6
|
-
|
|
7
|
-
## 快速开始
|
|
8
|
-
|
|
9
|
-
### 配置
|
|
10
|
-
|
|
11
|
-
在 `befly.*.json` 配置文件中配置 Redis:
|
|
12
|
-
|
|
13
|
-
```json
|
|
14
|
-
{
|
|
15
|
-
"redis": {
|
|
16
|
-
"host": "127.0.0.1",
|
|
17
|
-
"port": 6379,
|
|
18
|
-
"password": "",
|
|
19
|
-
"db": 0,
|
|
20
|
-
"prefix": "befly"
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
```
|
|
24
|
-
|
|
25
|
-
### 访问 Redis
|
|
26
|
-
|
|
27
|
-
通过 `befly.redis` 访问 Redis 助手实例:
|
|
28
|
-
|
|
29
|
-
```typescript
|
|
30
|
-
// 在 API handler 中
|
|
31
|
-
export default {
|
|
32
|
-
name: "示例接口",
|
|
33
|
-
handler: async (befly, ctx) => {
|
|
34
|
-
// 设置缓存
|
|
35
|
-
await befly.redis.setObject("user:1", { name: "张三", age: 25 });
|
|
36
|
-
|
|
37
|
-
// 获取缓存
|
|
38
|
-
const user = await befly.redis.getObject("user:1");
|
|
39
|
-
|
|
40
|
-
return befly.tool.Yes("成功", user);
|
|
41
|
-
}
|
|
42
|
-
};
|
|
43
|
-
```
|
|
44
|
-
|
|
45
|
-
---
|
|
46
|
-
|
|
47
|
-
## 核心方法
|
|
48
|
-
|
|
49
|
-
### 字符串操作
|
|
50
|
-
|
|
51
|
-
#### setString - 设置字符串
|
|
52
|
-
|
|
53
|
-
```typescript
|
|
54
|
-
// 基本设置
|
|
55
|
-
await befly.redis.setString("key", "value");
|
|
56
|
-
|
|
57
|
-
// 带过期时间(秒)
|
|
58
|
-
await befly.redis.setString("key", "value", 3600); // 1小时后过期
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
#### getString - 获取字符串
|
|
62
|
-
|
|
63
|
-
```typescript
|
|
64
|
-
const value = await befly.redis.getString("key");
|
|
65
|
-
// 返回: 'value' 或 null(不存在时)
|
|
66
|
-
```
|
|
67
|
-
|
|
68
|
-
### 对象操作
|
|
69
|
-
|
|
70
|
-
#### setObject - 设置对象
|
|
71
|
-
|
|
72
|
-
自动序列化为 JSON 存储。
|
|
73
|
-
|
|
74
|
-
```typescript
|
|
75
|
-
// 基本设置
|
|
76
|
-
await befly.redis.setObject("user:1", {
|
|
77
|
-
id: 1,
|
|
78
|
-
name: "张三",
|
|
79
|
-
roles: ["admin", "user"]
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
// 带过期时间(秒)
|
|
83
|
-
await befly.redis.setObject("session:abc123", { userId: 1 }, 7200); // 2小时
|
|
84
|
-
```
|
|
85
|
-
|
|
86
|
-
#### getObject - 获取对象
|
|
87
|
-
|
|
88
|
-
自动反序列化 JSON。
|
|
89
|
-
|
|
90
|
-
```typescript
|
|
91
|
-
const user = await befly.redis.getObject<UserInfo>("user:1");
|
|
92
|
-
// 返回: { id: 1, name: '张三', roles: ['admin', 'user'] } 或 null
|
|
93
|
-
```
|
|
94
|
-
|
|
95
|
-
#### delObject - 删除对象
|
|
96
|
-
|
|
97
|
-
```typescript
|
|
98
|
-
await befly.redis.delObject("user:1");
|
|
99
|
-
```
|
|
100
|
-
|
|
101
|
-
### 键操作
|
|
102
|
-
|
|
103
|
-
#### exists - 检查键是否存在
|
|
104
|
-
|
|
105
|
-
```typescript
|
|
106
|
-
const exists = await befly.redis.exists("user:1");
|
|
107
|
-
// 返回: true 或 false
|
|
108
|
-
```
|
|
109
|
-
|
|
110
|
-
#### del - 删除键
|
|
111
|
-
|
|
112
|
-
```typescript
|
|
113
|
-
const count = await befly.redis.del("user:1");
|
|
114
|
-
// 返回: 删除的键数量(0 或 1)
|
|
115
|
-
```
|
|
116
|
-
|
|
117
|
-
#### expire - 设置过期时间
|
|
118
|
-
|
|
119
|
-
```typescript
|
|
120
|
-
await befly.redis.expire("user:1", 3600); // 1小时后过期
|
|
121
|
-
```
|
|
122
|
-
|
|
123
|
-
#### ttl - 获取剩余过期时间
|
|
124
|
-
|
|
125
|
-
```typescript
|
|
126
|
-
const seconds = await befly.redis.ttl("user:1");
|
|
127
|
-
// 返回: 剩余秒数,-1 表示永不过期,-2 表示键不存在
|
|
128
|
-
```
|
|
129
|
-
|
|
130
|
-
### Set 集合操作
|
|
131
|
-
|
|
132
|
-
适用于存储不重复的元素集合,如权限列表、标签等。
|
|
133
|
-
|
|
134
|
-
#### sadd - 添加成员
|
|
135
|
-
|
|
136
|
-
```typescript
|
|
137
|
-
// 添加单个成员
|
|
138
|
-
await befly.redis.sadd("tags:article:1", ["技术"]);
|
|
139
|
-
|
|
140
|
-
// 添加多个成员
|
|
141
|
-
await befly.redis.sadd("user:1:roles", ["admin", "editor", "viewer"]);
|
|
142
|
-
```
|
|
143
|
-
|
|
144
|
-
#### sismember - 检查成员是否存在
|
|
145
|
-
|
|
146
|
-
```typescript
|
|
147
|
-
const isMember = await befly.redis.sismember("user:1:roles", "admin");
|
|
148
|
-
// 返回: true 或 false
|
|
149
|
-
```
|
|
150
|
-
|
|
151
|
-
#### smembers - 获取所有成员
|
|
152
|
-
|
|
153
|
-
```typescript
|
|
154
|
-
const roles = await befly.redis.smembers("user:1:roles");
|
|
155
|
-
// 返回: ['admin', 'editor', 'viewer']
|
|
156
|
-
```
|
|
157
|
-
|
|
158
|
-
#### scard - 获取成员数量
|
|
159
|
-
|
|
160
|
-
```typescript
|
|
161
|
-
const count = await befly.redis.scard("user:1:roles");
|
|
162
|
-
// 返回: 3
|
|
163
|
-
```
|
|
164
|
-
|
|
165
|
-
---
|
|
166
|
-
|
|
167
|
-
## 批量操作
|
|
168
|
-
|
|
169
|
-
批量操作利用 Bun Redis 的自动 pipeline 特性,显著提升性能。
|
|
170
|
-
|
|
171
|
-
### setBatch - 批量设置对象
|
|
172
|
-
|
|
173
|
-
```typescript
|
|
174
|
-
const count = await befly.redis.setBatch([
|
|
175
|
-
{ key: "user:1", value: { name: "张三" }, ttl: 3600 },
|
|
176
|
-
{ key: "user:2", value: { name: "李四" }, ttl: 3600 },
|
|
177
|
-
{ key: "user:3", value: { name: "王五" } } // 无 TTL,永不过期
|
|
178
|
-
]);
|
|
179
|
-
// 返回: 成功设置的数量
|
|
180
|
-
```
|
|
181
|
-
|
|
182
|
-
### getBatch - 批量获取对象
|
|
183
|
-
|
|
184
|
-
```typescript
|
|
185
|
-
const users = await befly.redis.getBatch<UserInfo>(["user:1", "user:2", "user:3"]);
|
|
186
|
-
// 返回: [{ name: '张三' }, { name: '李四' }, null](不存在的返回 null)
|
|
187
|
-
```
|
|
188
|
-
|
|
189
|
-
### delBatch - 批量删除键
|
|
190
|
-
|
|
191
|
-
```typescript
|
|
192
|
-
const count = await befly.redis.delBatch(["user:1", "user:2", "user:3"]);
|
|
193
|
-
// 返回: 成功删除的数量
|
|
194
|
-
```
|
|
195
|
-
|
|
196
|
-
### existsBatch - 批量检查存在
|
|
197
|
-
|
|
198
|
-
```typescript
|
|
199
|
-
const results = await befly.redis.existsBatch(["user:1", "user:2", "user:3"]);
|
|
200
|
-
// 返回: [true, true, false]
|
|
201
|
-
```
|
|
202
|
-
|
|
203
|
-
### ttlBatch - 批量获取过期时间
|
|
204
|
-
|
|
205
|
-
```typescript
|
|
206
|
-
const ttls = await befly.redis.ttlBatch(["user:1", "user:2", "user:3"]);
|
|
207
|
-
// 返回: [3600, 7200, -1]
|
|
208
|
-
```
|
|
209
|
-
|
|
210
|
-
### expireBatch - 批量设置过期时间
|
|
211
|
-
|
|
212
|
-
```typescript
|
|
213
|
-
const count = await befly.redis.expireBatch([
|
|
214
|
-
{ key: "user:1", seconds: 3600 },
|
|
215
|
-
{ key: "user:2", seconds: 7200 }
|
|
216
|
-
]);
|
|
217
|
-
// 返回: 成功设置的数量
|
|
218
|
-
```
|
|
219
|
-
|
|
220
|
-
### saddBatch - 批量添加 Set 成员
|
|
221
|
-
|
|
222
|
-
```typescript
|
|
223
|
-
import { CacheKeys } from "befly/lib/cacheKeys";
|
|
224
|
-
|
|
225
|
-
const count = await befly.redis.saddBatch([
|
|
226
|
-
{ key: CacheKeys.roleApis("admin"), members: ["/api/user"] },
|
|
227
|
-
{ key: CacheKeys.roleApis("editor"), members: ["/api/article"] }
|
|
228
|
-
]);
|
|
229
|
-
// 返回: 成功添加的总成员数量
|
|
230
|
-
```
|
|
231
|
-
|
|
232
|
-
### sismemberBatch - 批量检查 Set 成员
|
|
233
|
-
|
|
234
|
-
```typescript
|
|
235
|
-
import { CacheKeys } from "befly/lib/cacheKeys";
|
|
236
|
-
|
|
237
|
-
const results = await befly.redis.sismemberBatch([
|
|
238
|
-
{ key: CacheKeys.roleApis("admin"), member: "/api/user" },
|
|
239
|
-
{ key: CacheKeys.roleApis("admin"), member: "/api/user/delete" }
|
|
240
|
-
]);
|
|
241
|
-
// 返回: [true, false]
|
|
242
|
-
```
|
|
243
|
-
|
|
244
|
-
---
|
|
245
|
-
|
|
246
|
-
## 唯一 ID 生成
|
|
247
|
-
|
|
248
|
-
### genTimeID - 生成基于时间的唯一 ID
|
|
249
|
-
|
|
250
|
-
生成 16 位纯数字 ID,格式:`毫秒时间戳(13位) + 后缀(3位)`。
|
|
251
|
-
|
|
252
|
-
利用 Redis `INCR` 原子操作保证分布式环境下的唯一性。
|
|
253
|
-
|
|
254
|
-
```typescript
|
|
255
|
-
const id = await befly.redis.genTimeID();
|
|
256
|
-
// 返回: 1733395200000123(示例)
|
|
257
|
-
```
|
|
258
|
-
|
|
259
|
-
**使用场景:**
|
|
260
|
-
|
|
261
|
-
```typescript
|
|
262
|
-
// 在 DbHelper.insData 中自动调用
|
|
263
|
-
const id = await befly.db.insData({
|
|
264
|
-
table: "article",
|
|
265
|
-
data: {
|
|
266
|
-
title: "文章标题",
|
|
267
|
-
content: "文章内容"
|
|
268
|
-
}
|
|
269
|
-
});
|
|
270
|
-
// id 由 genTimeID 自动生成
|
|
271
|
-
```
|
|
272
|
-
|
|
273
|
-
**特点:**
|
|
274
|
-
|
|
275
|
-
- 16 位纯数字,可直接存储为 BIGINT
|
|
276
|
-
- 毫秒级时间戳 + 3 位后缀(100-999)
|
|
277
|
-
- 每毫秒支持 900 个并发 ID
|
|
278
|
-
- 分布式环境安全(基于 Redis INCR)
|
|
279
|
-
|
|
280
|
-
---
|
|
281
|
-
|
|
282
|
-
## 缓存键管理
|
|
283
|
-
|
|
284
|
-
### CacheKeys - 统一键名管理
|
|
285
|
-
|
|
286
|
-
避免硬编码,统一管理所有缓存键。
|
|
287
|
-
|
|
288
|
-
```typescript
|
|
289
|
-
import { CacheKeys } from "befly/lib/cacheKeys";
|
|
290
|
-
|
|
291
|
-
// 获取键名
|
|
292
|
-
const apisAllKey = CacheKeys.apisAll(); // 'apis:all'
|
|
293
|
-
const menusAllKey = CacheKeys.menusAll(); // 'menus:all'
|
|
294
|
-
const adminRoleInfoKey = CacheKeys.roleInfo("admin"); // 'role:info:admin'
|
|
295
|
-
const adminRoleApisKey = CacheKeys.roleApis("admin"); // 'role:apis:admin'
|
|
296
|
-
const userTableColumnsKey = CacheKeys.tableColumns("user"); // 'table:columns:user'
|
|
297
|
-
```
|
|
298
|
-
|
|
299
|
-
### 键名前缀
|
|
300
|
-
|
|
301
|
-
Redis 插件支持配置全局前缀,避免键名冲突:
|
|
302
|
-
|
|
303
|
-
```json
|
|
304
|
-
{
|
|
305
|
-
"redis": {
|
|
306
|
-
"prefix": "myapp"
|
|
307
|
-
}
|
|
308
|
-
}
|
|
309
|
-
```
|
|
310
|
-
|
|
311
|
-
所有键会自动添加前缀,最终写入 Redis 的 key 形如:`myapp:<key>`。
|
|
312
|
-
|
|
313
|
-
- 例如:你调用 `befly.redis.getString("user:1")`,实际访问的是 `myapp:user:1`
|
|
314
|
-
- 例如:你调用 `befly.redis.sismember(CacheKeys.roleApis("admin"), "/api/user")`,实际访问的是 `myapp:role:apis:admin`
|
|
315
|
-
|
|
316
|
-
> 注意:`redis.prefix` **不允许包含** `:`,因为 RedisHelper 会自动拼接分隔符 `:`。
|
|
317
|
-
|
|
318
|
-
---
|
|
319
|
-
|
|
320
|
-
## 实际应用场景
|
|
321
|
-
|
|
322
|
-
### 场景1:表结构缓存
|
|
323
|
-
|
|
324
|
-
DbHelper 自动缓存表字段信息,避免重复查询数据库。
|
|
325
|
-
|
|
326
|
-
```typescript
|
|
327
|
-
// 计数 + 过期:常用于限流/风控
|
|
328
|
-
// 更推荐:直接使用 Befly Core 内置的 rateLimit hook(通过 configs 配置即可)
|
|
329
|
-
|
|
330
|
-
const limit = 100; // 60 秒内最多 100 次
|
|
331
|
-
const windowSeconds = 60;
|
|
332
|
-
|
|
333
|
-
const key = `ratelimit:${ctx.ip}:${ctx.route}`;
|
|
334
|
-
const count = await befly.redis.incrWithExpire(key, windowSeconds);
|
|
335
|
-
|
|
336
|
-
if (count > limit) {
|
|
337
|
-
return befly.tool.No("请求过于频繁");
|
|
338
|
-
}
|
|
339
|
-
```
|
|
340
|
-
|
|
341
|
-
### 场景2:接口权限缓存
|
|
342
|
-
|
|
343
|
-
使用 Set 集合存储角色的接口权限,实现 O(1) 时间复杂度的权限检查。
|
|
344
|
-
|
|
345
|
-
```typescript
|
|
346
|
-
// 极简方案:每个角色一个 Set
|
|
347
|
-
const roleApisKey = CacheKeys.roleApis("admin");
|
|
348
|
-
const hasPermission = await befly.redis.sismember(roleApisKey, "/api/user/add");
|
|
349
|
-
// 返回: true
|
|
350
|
-
```
|
|
351
|
-
|
|
352
|
-
### 场景3:会话管理
|
|
353
|
-
|
|
354
|
-
```typescript
|
|
355
|
-
// 登录时创建会话
|
|
356
|
-
const sessionId = crypto.randomUUID();
|
|
357
|
-
await befly.redis.setObject(
|
|
358
|
-
`session:${sessionId}`,
|
|
359
|
-
{
|
|
360
|
-
userId: user.id,
|
|
361
|
-
username: user.username,
|
|
362
|
-
roleCode: user.roleCode,
|
|
363
|
-
loginTime: Date.now()
|
|
364
|
-
},
|
|
365
|
-
7200
|
|
366
|
-
); // 2小时过期
|
|
367
|
-
|
|
368
|
-
// 验证会话
|
|
369
|
-
const session = await befly.redis.getObject(`session:${sessionId}`);
|
|
370
|
-
if (!session) {
|
|
371
|
-
return befly.tool.No("会话已过期");
|
|
372
|
-
}
|
|
373
|
-
|
|
374
|
-
// 登出时删除会话
|
|
375
|
-
await befly.redis.delObject(`session:${sessionId}`);
|
|
376
|
-
```
|
|
377
|
-
|
|
378
|
-
### 场景4:Token 黑名单
|
|
379
|
-
|
|
380
|
-
```typescript
|
|
381
|
-
// 用户登出时,将 token 加入黑名单
|
|
382
|
-
const token = ctx.req.headers.get("Authorization")?.replace("Bearer ", "");
|
|
383
|
-
if (token) {
|
|
384
|
-
const key = `token:blacklist:${token}`;
|
|
385
|
-
await befly.redis.setString(key, "1", 7 * 24 * 60 * 60); // 7天
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
// 验证时检查黑名单
|
|
389
|
-
const isBlacklisted = await befly.redis.exists(`token:blacklist:${token}`);
|
|
390
|
-
if (isBlacklisted) {
|
|
391
|
-
return befly.tool.No("Token 已失效");
|
|
392
|
-
}
|
|
393
|
-
```
|
|
394
|
-
|
|
395
|
-
### 场景5:接口限流
|
|
396
|
-
|
|
397
|
-
```typescript
|
|
398
|
-
// 简单的滑动窗口限流
|
|
399
|
-
const key = `ratelimit:${ctx.ip}:${ctx.route}`;
|
|
400
|
-
const current = await befly.redis.getString(key);
|
|
401
|
-
const count = current ? parseInt(current) : 0;
|
|
402
|
-
|
|
403
|
-
if (count >= 100) {
|
|
404
|
-
// 每分钟最多 100 次
|
|
405
|
-
return befly.tool.No("请求过于频繁");
|
|
406
|
-
}
|
|
407
|
-
|
|
408
|
-
if (count === 0) {
|
|
409
|
-
await befly.redis.setString(key, "1", 60); // 60秒窗口
|
|
410
|
-
} else {
|
|
411
|
-
await befly.redis.setString(key, String(count + 1), await befly.redis.ttl(key));
|
|
412
|
-
}
|
|
413
|
-
```
|
|
414
|
-
|
|
415
|
-
### 场景6:分布式锁
|
|
416
|
-
|
|
417
|
-
```typescript
|
|
418
|
-
// 获取锁
|
|
419
|
-
const lockKey = `lock:order:${orderId}`;
|
|
420
|
-
const acquired = await befly.redis.setString(lockKey, "1", 30); // 30秒自动释放
|
|
421
|
-
|
|
422
|
-
if (!acquired) {
|
|
423
|
-
return befly.tool.No("操作正在进行中,请稍后");
|
|
424
|
-
}
|
|
425
|
-
|
|
426
|
-
try {
|
|
427
|
-
// 执行业务逻辑
|
|
428
|
-
await processOrder(orderId);
|
|
429
|
-
} finally {
|
|
430
|
-
// 释放锁
|
|
431
|
-
await befly.redis.del(lockKey);
|
|
432
|
-
}
|
|
433
|
-
```
|
|
434
|
-
|
|
435
|
-
### 场景7:数据缓存
|
|
436
|
-
|
|
437
|
-
```typescript
|
|
438
|
-
// 获取热门文章(带缓存)
|
|
439
|
-
const cacheKey = "articles:hot:10";
|
|
440
|
-
let articles = await befly.redis.getObject(cacheKey);
|
|
441
|
-
|
|
442
|
-
if (!articles) {
|
|
443
|
-
// 缓存未命中,查询数据库
|
|
444
|
-
const result = await befly.db.getAll({
|
|
445
|
-
table: "article",
|
|
446
|
-
fields: ["id", "title", "viewCount"],
|
|
447
|
-
orderBy: ["viewCount#DESC"]
|
|
448
|
-
});
|
|
449
|
-
|
|
450
|
-
articles = result.lists; // 获取数据列表(最多 10000 条)
|
|
451
|
-
|
|
452
|
-
// 写入缓存,5分钟过期
|
|
453
|
-
await befly.redis.setObject(cacheKey, articles, 300);
|
|
454
|
-
}
|
|
455
|
-
|
|
456
|
-
return befly.tool.Yes("成功", articles);
|
|
457
|
-
```
|
|
458
|
-
|
|
459
|
-
---
|
|
460
|
-
|
|
461
|
-
## CacheHelper 缓存助手
|
|
462
|
-
|
|
463
|
-
框架内置的缓存助手,管理接口、菜单和角色权限的缓存。
|
|
464
|
-
|
|
465
|
-
### 服务启动时自动缓存
|
|
466
|
-
|
|
467
|
-
```typescript
|
|
468
|
-
// 框架启动时自动调用
|
|
469
|
-
await befly.cache.cacheAll();
|
|
470
|
-
|
|
471
|
-
// 等同于依次执行:
|
|
472
|
-
await befly.cache.cacheApis(); // 缓存接口列表
|
|
473
|
-
await befly.cache.cacheMenus(); // 缓存菜单列表
|
|
474
|
-
await befly.cache.cacheRolePermissions(); // 缓存角色权限
|
|
475
|
-
```
|
|
476
|
-
|
|
477
|
-
### 获取缓存数据
|
|
478
|
-
|
|
479
|
-
```typescript
|
|
480
|
-
// 获取所有接口
|
|
481
|
-
const apis = await befly.cache.getApis();
|
|
482
|
-
|
|
483
|
-
// 获取所有菜单
|
|
484
|
-
const menus = await befly.cache.getMenus();
|
|
485
|
-
|
|
486
|
-
// 获取角色权限
|
|
487
|
-
const permissions = await befly.cache.getRolePermissions("admin");
|
|
488
|
-
// 返回: ['/api/user/list', '/api/user/add', ...]
|
|
489
|
-
```
|
|
490
|
-
|
|
491
|
-
### 权限检查
|
|
492
|
-
|
|
493
|
-
```typescript
|
|
494
|
-
// 检查角色是否有指定接口权限
|
|
495
|
-
const hasPermission = await befly.cache.checkRolePermission("admin", "/api/user/add");
|
|
496
|
-
// 返回: true 或 false
|
|
497
|
-
```
|
|
498
|
-
|
|
499
|
-
### 更新缓存
|
|
500
|
-
|
|
501
|
-
角色权限变更后,需要刷新缓存:
|
|
502
|
-
|
|
503
|
-
```typescript
|
|
504
|
-
// 删除指定角色的权限缓存
|
|
505
|
-
await befly.cache.deleteRolePermissions("admin");
|
|
506
|
-
|
|
507
|
-
// 重新缓存所有角色权限
|
|
508
|
-
await befly.cache.cacheRolePermissions();
|
|
509
|
-
```
|
|
510
|
-
|
|
511
|
-
---
|
|
512
|
-
|
|
513
|
-
## 性能优化
|
|
514
|
-
|
|
515
|
-
### 1. 利用 Bun 自动 Pipeline
|
|
516
|
-
|
|
517
|
-
Bun Redis 客户端自动将多个并发请求合并为 pipeline,无需手动处理。
|
|
518
|
-
|
|
519
|
-
```typescript
|
|
520
|
-
// 这些请求会自动合并为一个 pipeline
|
|
521
|
-
const [user1, user2, user3] = await Promise.all([befly.redis.getObject("user:1"), befly.redis.getObject("user:2"), befly.redis.getObject("user:3")]);
|
|
522
|
-
```
|
|
523
|
-
|
|
524
|
-
### 2. 使用批量方法
|
|
525
|
-
|
|
526
|
-
对于明确的批量操作,使用专用的批量方法:
|
|
527
|
-
|
|
528
|
-
```typescript
|
|
529
|
-
// ✅ 推荐:使用批量方法
|
|
530
|
-
const users = await befly.redis.getBatch(["user:1", "user:2", "user:3"]);
|
|
531
|
-
|
|
532
|
-
// ❌ 不推荐:循环调用
|
|
533
|
-
const users = [];
|
|
534
|
-
for (const id of [1, 2, 3]) {
|
|
535
|
-
users.push(await befly.redis.getObject(`user:${id}`));
|
|
536
|
-
}
|
|
537
|
-
```
|
|
538
|
-
|
|
539
|
-
### 3. 合理设置 TTL
|
|
540
|
-
|
|
541
|
-
```typescript
|
|
542
|
-
// 高频访问、变化少的数据 - 较长 TTL
|
|
543
|
-
await befly.redis.setObject("config:system", config, 86400); // 24小时
|
|
544
|
-
|
|
545
|
-
// 实时性要求高的数据 - 较短 TTL
|
|
546
|
-
await befly.redis.setObject("stats:online", count, 60); // 1分钟
|
|
547
|
-
|
|
548
|
-
// 永久缓存(慎用)
|
|
549
|
-
await befly.redis.setObject("constants:provinces", provinces); // 无 TTL
|
|
550
|
-
```
|
|
551
|
-
|
|
552
|
-
### 4. 避免大 Key
|
|
553
|
-
|
|
554
|
-
```typescript
|
|
555
|
-
// ❌ 避免:存储大量数据在单个 key
|
|
556
|
-
await befly.redis.setObject("all:users", hugeUserList); // 可能有 10MB+
|
|
557
|
-
|
|
558
|
-
// ✅ 推荐:分散存储
|
|
559
|
-
for (const user of users) {
|
|
560
|
-
await befly.redis.setObject(`user:${user.id}`, user);
|
|
561
|
-
}
|
|
562
|
-
```
|
|
563
|
-
|
|
564
|
-
---
|
|
565
|
-
|
|
566
|
-
## 连接测试
|
|
567
|
-
|
|
568
|
-
```typescript
|
|
569
|
-
// 测试 Redis 连接
|
|
570
|
-
const pong = await befly.redis.ping();
|
|
571
|
-
// 返回: 'PONG'
|
|
572
|
-
```
|
|
573
|
-
|
|
574
|
-
---
|
|
575
|
-
|
|
576
|
-
## 错误处理
|
|
577
|
-
|
|
578
|
-
所有 Redis 方法都内置了错误处理,不会抛出异常:
|
|
579
|
-
|
|
580
|
-
```typescript
|
|
581
|
-
// 操作失败时返回默认值,不会中断程序
|
|
582
|
-
const value = await befly.redis.getObject("key"); // 返回 null
|
|
583
|
-
const exists = await befly.redis.exists("key"); // 返回 false
|
|
584
|
-
const count = await befly.redis.del("key"); // 返回 0
|
|
585
|
-
|
|
586
|
-
// 错误会记录到日志
|
|
587
|
-
// Logger.error('Redis getObject 错误', error);
|
|
588
|
-
```
|
|
589
|
-
|
|
590
|
-
如需捕获错误,可以检查返回值:
|
|
591
|
-
|
|
592
|
-
```typescript
|
|
593
|
-
const result = await befly.redis.setObject("key", data);
|
|
594
|
-
if (result === null) {
|
|
595
|
-
Logger.warn("缓存写入失败");
|
|
596
|
-
// 降级处理...
|
|
597
|
-
}
|
|
598
|
-
```
|
|
599
|
-
|
|
600
|
-
---
|
|
601
|
-
|
|
602
|
-
## 方法速查表
|
|
603
|
-
|
|
604
|
-
| 方法 | 说明 | 返回值 |
|
|
605
|
-
| ---------------- | ----------------- | ------------------ |
|
|
606
|
-
| `setString` | 设置字符串 | `'OK'` / `null` |
|
|
607
|
-
| `getString` | 获取字符串 | `string` / `null` |
|
|
608
|
-
| `setObject` | 设置对象(JSON) | `'OK'` / `null` |
|
|
609
|
-
| `getObject` | 获取对象(JSON) | `T` / `null` |
|
|
610
|
-
| `delObject` | 删除对象 | `void` |
|
|
611
|
-
| `exists` | 检查键是否存在 | `boolean` |
|
|
612
|
-
| `del` | 删除键 | `number` |
|
|
613
|
-
| `expire` | 设置过期时间 | `number` |
|
|
614
|
-
| `ttl` | 获取剩余过期时间 | `number` |
|
|
615
|
-
| `sadd` | 添加 Set 成员 | `number` |
|
|
616
|
-
| `sismember` | 检查 Set 成员 | `boolean` |
|
|
617
|
-
| `smembers` | 获取所有 Set 成员 | `string[]` |
|
|
618
|
-
| `scard` | 获取 Set 成员数量 | `number` |
|
|
619
|
-
| `genTimeID` | 生成唯一 ID | `number` |
|
|
620
|
-
| `ping` | 测试连接 | `'PONG'` |
|
|
621
|
-
| `setBatch` | 批量设置对象 | `number` |
|
|
622
|
-
| `getBatch` | 批量获取对象 | `Array<T \| null>` |
|
|
623
|
-
| `delBatch` | 批量删除键 | `number` |
|
|
624
|
-
| `existsBatch` | 批量检查存在 | `boolean[]` |
|
|
625
|
-
| `ttlBatch` | 批量获取 TTL | `number[]` |
|
|
626
|
-
| `expireBatch` | 批量设置过期时间 | `number` |
|
|
627
|
-
| `saddBatch` | 批量添加 Set 成员 | `number` |
|
|
628
|
-
| `sismemberBatch` | 批量检查 Set 成员 | `boolean[]` |
|