chanjs 2.7.4 → 2.7.6

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.
Files changed (94) hide show
  1. package/USAGE.md +533 -0
  2. package/config/index.js +37 -6
  3. package/core/App.js +166 -0
  4. package/core/BaseComponent.js +27 -0
  5. package/core/Container.js +68 -0
  6. package/core/Controller.js +29 -0
  7. package/core/Database.js +93 -0
  8. package/core/Repository.js +323 -0
  9. package/core/Service.js +11 -0
  10. package/core/bootstrap/error-handler.js +101 -0
  11. package/core/bootstrap/hook-runner.js +64 -0
  12. package/core/bootstrap/middleware.js +35 -0
  13. package/core/bootstrap/router-loader.js +53 -0
  14. package/core/errors.js +251 -0
  15. package/core/loader.js +89 -0
  16. package/core/registry.js +17 -0
  17. package/doc/Cache.md +279 -106
  18. package/doc/Common.md +590 -134
  19. package/doc/Controller.md +166 -95
  20. package/doc/Help.md +299 -698
  21. package/doc/QuickStart.md +116 -0
  22. package/doc/Repository.md +560 -0
  23. package/doc/Service.md +201 -527
  24. package/index.js +61 -37
  25. package/middleware/body.js +17 -0
  26. package/middleware/cookie.js +7 -15
  27. package/middleware/cors.js +9 -27
  28. package/middleware/favicon.js +15 -17
  29. package/middleware/header.js +15 -16
  30. package/middleware/index.js +11 -11
  31. package/middleware/log.js +26 -56
  32. package/middleware/static.js +15 -28
  33. package/middleware/template.js +75 -115
  34. package/middleware/validate.js +79 -0
  35. package/middleware/waf.js +176 -197
  36. package/package.json +9 -2
  37. package/response/code.js +73 -0
  38. package/response/index.js +9 -6
  39. package/response/response.js +82 -236
  40. package/security/checker.js +26 -74
  41. package/security/index.js +4 -9
  42. package/security/jwt.js +84 -139
  43. package/security/keywords.js +33 -137
  44. package/security/rate-limit.js +38 -80
  45. package/security/sign.js +83 -176
  46. package/security/xss-filter.js +21 -53
  47. package/storage/cache.js +58 -198
  48. package/storage/index.js +3 -6
  49. package/storage/redis.js +124 -181
  50. package/storage/store.js +163 -188
  51. package/utils/data-parse.js +42 -186
  52. package/utils/file.js +73 -244
  53. package/utils/filter.js +22 -25
  54. package/utils/html.js +49 -33
  55. package/utils/index.js +20 -7
  56. package/utils/ip.js +31 -71
  57. package/utils/logger.js +117 -0
  58. package/utils/pages.js +55 -0
  59. package/utils/paths.js +18 -0
  60. package/utils/request.js +95 -136
  61. package/utils/signal.js +87 -0
  62. package/utils/time.js +33 -75
  63. package/utils/tree.js +112 -104
  64. package/App.js +0 -533
  65. package/base/Aop.js +0 -195
  66. package/base/Container.js +0 -161
  67. package/base/Controller.js +0 -65
  68. package/base/Database.js +0 -133
  69. package/base/Event.js +0 -61
  70. package/base/Repository.js +0 -644
  71. package/common/api.js +0 -35
  72. package/common/code.js +0 -52
  73. package/common/email.js +0 -191
  74. package/common/index.js +0 -5
  75. package/common/pages.js +0 -120
  76. package/common/utils.js +0 -73
  77. package/config/code.js +0 -166
  78. package/config/paths.js +0 -60
  79. package/doc/Aop.md +0 -269
  80. package/doc/Email.md +0 -114
  81. package/doc/Event.md +0 -232
  82. package/global/env.js +0 -11
  83. package/global/import.js +0 -39
  84. package/global/index.js +0 -8
  85. package/helper/index.js +0 -79
  86. package/loader/index.js +0 -6
  87. package/loader/loader.js +0 -138
  88. package/middleware/compress.js +0 -185
  89. package/middleware/setBody.js +0 -32
  90. package/realtime/index.js +0 -7
  91. package/realtime/sse.js +0 -424
  92. package/realtime/websocket.js +0 -540
  93. package/schedule/index.js +0 -6
  94. package/schedule/schedule.js +0 -491
package/doc/Help.md CHANGED
@@ -1,789 +1,390 @@
1
- # chanjs/helper/index.js 工具函数使用文档
2
- 本文档详细说明 `chanjs/helper/index.js` 导出的所有工具函数的调用方式、参数说明及使用示例,帮助开发者快速集成和使用这些工具。
1
+ # ChanJS 框架 API 参考
3
2
 
4
- ## 一、加载器相关(loader.js)
5
- ### 1. loaderSort
6
- **功能**:对加载的模块/配置进行排序处理
7
- **调用方式**:
8
- ```javascript
9
- import { loaderSort } from 'chanjs/helper/index.js';
3
+ ## 概述
10
4
 
11
- // 示例:对加载的控制器列表排序
12
- const loadList = [{ name: 'user', order: 2 }, { name: 'auth', order: 1 }];
13
- const sortedList = loaderSort(loadList); // 按order升序排列
14
- console.log(sortedList); // [{ name: 'auth', order: 1 }, { name: 'user', order: 2 }]
15
- ```
16
- **参数说明**:
17
- - `list` (Array):需要排序的加载项数组,数组项需包含排序字段(如`order`,具体字段由内部逻辑定义)
18
- - 返回值:排序后的数组
5
+ ChanJS 是基于 Express 5 的轻量级 Node.js MVC 框架,采用纯 JavaScript(ESM)编写。本文档汇总框架所有对外暴露的 API。
6
+
7
+ ## 包入口
19
8
 
20
- ### 2. loadConfig
21
- **功能**:加载项目配置文件(如JSON/JS配置)
22
- **调用方式**:
23
9
  ```javascript
24
- import { loadConfig } from 'chanjs/helper/index.js';
10
+ import Chan from 'chanjs'; // 默认导出:应用主类
25
11
 
26
- // 示例:加载指定路径的配置
27
- const config = loadConfig('config/app.js');
28
- console.log(config); // 配置文件导出的内容
12
+ // 命名导出
13
+ import {
14
+ Controller, Repository, Service,
15
+ AppError, NotFoundError, ValidationError, BusinessError,
16
+ // ... 更多错误类
17
+ describeError, errorExtraProps, parseStack, isAppError, wrapDbError,
18
+ success, fail, routeNotFound, serializeError, buildErrorHtml, respondError,
19
+ setToken, getToken, verifyToken,
20
+ aesEncrypt, aesDecrypt,
21
+ logger, createLogger,
22
+ validate, validateAll,
23
+ setApp, getApp,
24
+ loader, utils,
25
+ cache, store, Paths,
26
+ helper
27
+ } from 'chanjs';
29
28
  ```
30
- **参数说明**:
31
- - `path` (String):配置文件路径(相对/绝对)
32
- - 返回值:配置文件的导出内容
33
29
 
34
- ### 3. clearConfigCache
35
- **功能**:清除配置加载的缓存(避免配置修改后读取旧值)
36
- **调用方式**:
37
- ```javascript
38
- import { clearConfigCache } from 'chanjs/helper/index.js';
30
+ ## 核心类
39
31
 
40
- // 示例:修改配置后清除缓存
41
- clearConfigCache(); // 无参数,直接调用
42
- ```
43
- **参数说明**:无参数
44
- **返回值**:无
32
+ ### Chan - 应用主类
45
33
 
46
- ### 4. loadController
47
- **功能**:加载指定目录下的控制器文件
48
- **调用方式**:
49
34
  ```javascript
50
- import { loadController } from 'chanjs/helper/index.js';
51
-
52
- // 示例:加载controllers目录下的所有控制器
53
- const controllers = loadController('app/controllers');
54
- console.log(controllers); // 控制器实例/映射对象
35
+ const app = new Chan();
36
+ await app.start();
37
+ app.run(port => console.log(`监听端口 ${port}`));
55
38
  ```
56
- **参数说明**:
57
- - `dir` (String):控制器目录路径
58
- - 返回值:加载后的控制器集合(对象/数组,具体格式由内部逻辑定义)
59
-
60
- ## 二、时间处理(time.js)
61
- ### 1. formatTime
62
- **功能**:格式化时间戳/日期对象为指定格式的字符串
63
- **调用方式**:
64
- ```javascript
65
- import { formatTime } from 'chanjs/helper/index.js';
66
39
 
67
- // 示例1:格式化当前时间
68
- const now = new Date();
69
- const timeStr1 = formatTime(now, 'YYYY-MM-DD HH:mm:ss'); // 2024-05-20 14:30:00
40
+ | 方法 | 说明 |
41
+ |------|------|
42
+ | `start()` | 完整启动流程(配置→缓存→数据库→中间件→路由→错误处理→钩子) |
43
+ | `run(cb)` | 启动 HTTP 监听,`cb(port)` 回调接收端口号 |
44
+ | `beforeStart(fn)` | 注册启动前置钩子 |
45
+ | `shutdown()` | 执行优雅停机 |
46
+
47
+ ### Controller - 控制器基类
70
48
 
71
- // 示例2:格式化时间戳
72
- const timestamp = 1716205800000;
73
- const timeStr2 = formatTime(timestamp, 'YYYY/MM/DD'); // 2024/05/20
74
- ```
75
- **参数说明**:
76
- - `time` (Date/Number/String):待格式化的时间(日期对象/时间戳/时间字符串)
77
- - `format` (String):格式模板,支持 `YYYY`(年)、`MM`(月)、`DD`(日)、`HH`(时)、`mm`(分)、`ss`(秒)
78
- - 返回值:格式化后的时间字符串
79
-
80
- ### 2. formatDateFields
81
- **功能**:批量格式化对象中的日期字段(如将时间戳字段转为格式化字符串)
82
- **调用方式**:
83
49
  ```javascript
84
- import { formatDateFields } from 'chanjs/helper/index.js';
85
-
86
- // 示例:格式化对象中的createTime和updateTime字段
87
- const data = {
88
- id: 1,
89
- createTime: 1716205800000,
90
- updateTime: 1716206800000
91
- };
92
- const formattedData = formatDateFields(data, ['createTime', 'updateTime'], 'YYYY-MM-DD');
93
- // { id: 1, createTime: '2024-05-20', updateTime: '2024-05-20' }
50
+ class UserController extends Controller {
51
+ async getUser(req, res) {
52
+ return this.success({ data: { id: 1 } });
53
+ }
54
+ }
94
55
  ```
95
- **参数说明**:
96
- - `obj` (Object):需要处理的对象
97
- - `fields` (Array):需要格式化的日期字段名数组
98
- - `format` (String):时间格式模板(同formatTime)
99
- - 返回值:格式化后的新对象
100
-
101
- ## 三、缓存相关(cache.js)
102
- ### 1. Cache(默认导出类)
103
- **功能**:缓存操作类(支持设置、获取、删除缓存等)
104
- **调用方式**:
56
+
57
+ | 方法 | 说明 |
58
+ |------|------|
59
+ | `success({ data, msg })` | 成功响应,默认 code=0 |
60
+ | `fail(opts)` | 失败响应,支持字符串简写或对象配置,默认 code=1008 |
61
+
62
+ ### Repository - 数据访问基类
63
+
105
64
  ```javascript
106
- import { Cache } from 'chanjs/helper/index.js';
65
+ class UserRepo extends Repository {
66
+ constructor() {
67
+ super('users'); // 表名
68
+ }
69
+ }
70
+ ```
107
71
 
108
- // 示例:实例化并使用缓存
109
- const cache = new Cache();
72
+ | 方法 | 说明 |
73
+ |------|------|
74
+ | `all({ query, sort, fields, limit })` | 查询全部,默认上限 1000 条 |
75
+ | `find({ query, sort, fields, limit, offset })` | 分页偏移查询 |
76
+ | `findOne({ query, fields })` | 查询单条 |
77
+ | `findById(id, { fields })` | 根据 ID 查询 |
78
+ | `insert(data)` | 单条插入 |
79
+ | `insertMany(records)` | 批量插入 |
80
+ | `del(query)` | 条件删除 |
81
+ | `deleteById(id)` | 根据 ID 删除 |
82
+ | `deleteMany(ids)` | 批量删除 |
83
+ | `updateByQuery({ query, data })` | 条件更新 |
84
+ | `updateById(id, data)` | 根据 ID 更新 |
85
+ | `updateMany(updates)` | 事务批量更新 |
86
+ | `query({ current, pageSize, query, sort, field })` | 标准分页查询 |
87
+ | `count(query)` | 统计行数 |
88
+ | `exists(query)` | 判断是否存在 |
89
+ | `join({ joinTable, localField, foreignField, fields, query, sort })` | 联表查询 |
90
+ | `stats()` | 统计总数 + 今日新增 |
91
+
92
+ ### Service - 服务基类
93
+
94
+ ```javascript
95
+ class UserService extends Service {
96
+ constructor() {
97
+ super();
98
+ this.userRepo = new UserRepo();
99
+ }
100
+ }
101
+ ```
110
102
 
111
- // 设置缓存(key, value, 过期时间(秒))
112
- cache.set('user_1', { name: '张三' }, 3600);
103
+ Service 是纯业务逻辑层,不包含 CRUD 方法。通过注入 Repository 实例进行数据操作。
113
104
 
114
- // 获取缓存
115
- const user = cache.get('user_1');
116
- console.log(user); // { name: '张三' }
105
+ ## 错误体系
117
106
 
118
- // 删除缓存
119
- cache.del('user_1');
107
+ ### 错误类
120
108
 
121
- // 清空所有缓存
122
- cache.clear();
123
- ```
124
- **核心方法**:
125
- - `set(key, value, expire)`:设置缓存,`expire` 为过期时间(秒),可选
126
- - `get(key)`:获取缓存,返回缓存值(无则返回null)
127
- - `del(key)`:删除指定key的缓存
128
- - `clear()`:清空所有缓存
129
-
130
- ## 四、文件操作(file.js)
131
- ### 1. dirname
132
- **功能**:获取文件/路径的目录名(兼容不同系统路径)
133
- **调用方式**:
134
- ```javascript
135
- import { dirname } from 'chanjs/helper/index.js';
109
+ | 类名 | 默认 code | HTTP 状态 | 默认提示 |
110
+ |------|-----------|-----------|----------|
111
+ | `AppError` | - | - | 基础类 |
112
+ | `AuthError` | 1001 | 401 | 认证失败 |
113
+ | `TokenExpiredError` | 1002 | 401 | 令牌已过期 |
114
+ | `ForbiddenError` | 1003 | 403 | 权限不足 |
115
+ | `NotFoundError` | 1004 | 404 | 资源不存在 |
116
+ | `ConflictError` | 1005 | 409 | 资源已存在 |
117
+ | `ValidationError` | 1006 | 422 | 参数无效 |
118
+ | `ParamMissingError` | 1007 | 400 | 参数缺失 |
119
+ | `BusinessError` | 1008 | 400 | 业务处理失败 |
120
+ | `RateLimitError` | 1009 | 429 | 请求过于频繁 |
121
+ | `BlockedError` | 1011 | 403 | 访问已被限制 |
122
+ | `SystemError` | 5001 | 500 | 系统内部错误 |
123
+ | `ServiceBusyError` | 5002 | 503 | 服务繁忙 |
124
+ | `DbConnectionError` | 6001 | 503 | 数据库连接失败 |
125
+ | `DbAccessDeniedError` | 6002 | 503 | 数据库访问被拒绝 |
126
+ | `DbTimeoutError` | 6007 | 503 | 数据库操作超时 |
136
127
 
137
- // 示例:获取文件的目录路径
138
- const filePath = '/app/controllers/user.js';
139
- const dir = dirname(filePath);
140
- console.log(dir); // /app/controllers
141
- ```
142
- **参数说明**:
143
- - `path` (String):文件/路径字符串
144
- - 返回值:目录名字符串
128
+ ### 错误类使用
145
129
 
146
- ### 2. delImg
147
- **功能**:删除指定路径的图片文件
148
- **调用方式**:
149
130
  ```javascript
150
- import { delImg } from 'chanjs/helper/index.js';
131
+ // 字符串简写
132
+ throw new NotFoundError('用户不存在');
133
+
134
+ // 对象配置
135
+ throw new ValidationError({
136
+ msg: '参数校验失败',
137
+ fields: ['name', 'email']
138
+ });
151
139
 
152
- // 示例:删除上传的图片
153
- const imgPath = '/uploads/2024/05/avatar.png';
154
- const isDel = delImg(imgPath);
155
- console.log(isDel); // true(删除成功)/false(删除失败)
140
+ // 带底层 cause
141
+ throw new SystemError('系统异常', originalError);
156
142
  ```
157
- **参数说明**:
158
- - `imgPath` (String):图片文件路径
159
- - 返回值:Boolean,是否删除成功
160
143
 
161
- ### 3. getFileTree
162
- **功能**:生成指定目录的文件树结构(递归遍历)
163
- **调用方式**:
164
- ```javascript
165
- import { getFileTree } from 'chanjs/helper/index.js';
144
+ ### 错误工具函数
166
145
 
167
- // 示例:生成src目录的文件树
168
- const tree = getFileTree('/app/src');
169
- console.log(tree);
170
- // 输出示例:{ name: 'src', type: 'dir', children: [{ name: 'utils', type: 'dir', children: [...] }, ...] }
171
- ```
172
- **参数说明**:
173
- - `dir` (String):目标目录路径
174
- - 返回值:Object,文件树结构(包含name、type、children等字段)
146
+ | 函数 | 说明 |
147
+ |------|------|
148
+ | `isAppError(err)` | 判断是否为业务错误实例 |
149
+ | `describeError(err)` | 递归解析完整可读错误信息 |
150
+ | `errorExtraProps(err)` | 提取错误自定义附加属性 |
151
+ | `wrapDbError(err)` | 将数据库原生错误转换为 AppError 子类 |
152
+ | `parseStack(stack)` | 解析 V8 堆栈,提取报错文件和行号 |
175
153
 
176
- ### 4. readFileContent
177
- **功能**:读取文件内容(支持文本/JSON格式)
178
- **调用方式**:
179
- ```javascript
180
- import { readFileContent } from 'chanjs/helper/index.js';
154
+ ## 响应工具
181
155
 
182
- // 示例1:读取文本文件
183
- const text = readFileContent('/app/config.txt', 'utf8');
184
- console.log(text); // 文件文本内容
156
+ | 函数 | 说明 |
157
+ |------|------|
158
+ | `success({ data, msg })` | 成功响应,code=0 |
159
+ | `fail({ msg, code, data })` | 失败响应,默认 code=1008 |
160
+ | `routeNotFound(req)` | 404 路由不存在响应 |
161
+ | `serializeError(err, exposeDetail)` | 统一错误序列化 |
162
+ | `buildErrorHtml(status, msg, code, req)` | 构建错误 HTML 页面 |
163
+ | `respondError(res, req, opts, apiPrefixes)` | 统一错误响应出口(HTML/JSON 自动分流) |
164
+
165
+ ## 安全工具
166
+
167
+ ### JWT
185
168
 
186
- // 示例2:读取JSON文件
187
- const json = readFileContent('/app/config.json', 'json');
188
- console.log(json); // 解析后的JSON对象
189
- ```
190
- **参数说明**:
191
- - `filePath` (String):文件路径
192
- - `type` (String):读取类型,可选 `utf8`(文本)/`json`(JSON),默认`utf8`
193
- - 返回值:String/Object,文件内容(JSON类型返回解析后的对象)
194
-
195
- ### 5. saveFileContent
196
- **功能**:写入内容到文件(支持覆盖/追加)
197
- **调用方式**:
198
169
  ```javascript
199
- import { saveFileContent } from 'chanjs/helper/index.js';
170
+ import { setToken, getToken, verifyToken } from 'chanjs';
200
171
 
201
- // 示例1:覆盖写入文本
202
- saveFileContent('/app/log.txt', '操作日志:用户登录', 'overwrite');
172
+ // 签发令牌
173
+ const token = setToken({ userId: 1 }, secretKey, '7d');
203
174
 
204
- // 示例2:追加写入文本
205
- saveFileContent('/app/log.txt', '\n操作日志:用户退出', 'append');
175
+ // 校验令牌(详细结果)
176
+ const result = await verifyToken(token, secretKey);
177
+ // { valid: true, reason: 'ok', payload: {...} }
178
+ // { valid: false, reason: 'expired' | 'invalid' | 'revoked' | 'missing' }
206
179
 
207
- // 示例3:写入JSON对象
208
- saveFileContent('/app/data.json', { list: [1,2,3] }, 'json');
180
+ // 校验令牌(成功返回载荷,失败返回 null)
181
+ const payload = await getToken(token, secretKey);
209
182
  ```
210
- **参数说明**:
211
- - `filePath` (String):文件路径
212
- - `content` (String/Object):写入内容(JSON类型自动序列化)
213
- - `mode` (String):写入模式,可选 `overwrite`(覆盖)/`append`(追加)/`json`(JSON写入),默认`overwrite`
214
- - 返回值:Boolean,是否写入成功
215
-
216
- ### 6. isPathSafe
217
- **功能**:校验路径是否安全(防止路径遍历攻击)
218
- **调用方式**:
219
- ```javascript
220
- import { isPathSafe } from 'chanjs/helper/index.js';
221
183
 
222
- // 示例1:安全路径
223
- const safe = isPathSafe('/app/uploads/avatar.png', '/app/uploads');
224
- console.log(safe); // true
184
+ ### AES 加解密
225
185
 
226
- // 示例2:危险路径(路径遍历)
227
- const unsafe = isPathSafe('/app/uploads/../config.js', '/app/uploads');
228
- console.log(unsafe); // false
229
- ```
230
- **参数说明**:
231
- - `path` (String):待校验的路径
232
- - `root` (String):允许的根目录
233
- - 返回值:Boolean,路径是否安全
234
-
235
- ### 7. getFolders
236
- **功能**:获取指定目录下的所有子目录
237
- **调用方式**:
238
186
  ```javascript
239
- import { getFolders } from 'chanjs/helper/index.js';
187
+ import { aesEncrypt, aesDecrypt } from 'chanjs';
240
188
 
241
- // 示例:获取src目录下的所有子目录
242
- const folders = getFolders('/app/src');
243
- console.log(folders); // ['utils', 'controllers', 'models']
189
+ const encrypted = await aesEncrypt('敏感数据', secretKey);
190
+ const decrypted = await aesDecrypt(encrypted, secretKey);
244
191
  ```
245
- **参数说明**:
246
- - `dir` (String):目标目录路径
247
- - 返回值:Array,子目录名称数组
248
-
249
- ## 五、HTML处理(html.js)
250
- ### 1. htmlDecode
251
- **功能**:HTML实体解码(将`&`/`<`等转为原字符)
252
- **调用方式**:
253
- ```javascript
254
- import { htmlDecode } from 'chanjs/helper/index.js';
255
192
 
256
- // 示例:解码HTML实体
257
- const htmlStr = '<div>张三&李四</div>';
258
- const rawStr = htmlDecode(htmlStr);
259
- console.log(rawStr); // <div>张三&李四</div>
260
- ```
261
- **参数说明**:
262
- - `str` (String):包含HTML实体的字符串
263
- - 返回值:String,解码后的原始字符串
264
-
265
- ## 六、IP相关(ip.js)
266
- ### 1. getIp
267
- **功能**:从请求对象中获取客户端真实IP(兼容反向代理)
268
- **调用方式**:
269
- ```javascript
270
- import { getIp } from 'chanjs/helper/index.js';
271
- // 示例(Express/Koa框架)
272
- app.get('/', (req, res) => {
273
- const ip = getIp(req); // Koa需传req.req
274
- console.log(ip); // 客户端IP,如 192.168.1.100
275
- res.send(`你的IP:${ip}`);
276
- });
277
- ```
278
- **参数说明**:
279
- - `req` (Object):HTTP请求对象(Express/Koa的req)
280
- - 返回值:String,客户端真实IP
281
-
282
- ## 七、JWT令牌(jwt.js)
283
- ### 1. verifyToken
284
- **功能**:验证JWT令牌的有效性
285
- **调用方式**:
286
- ```javascript
287
- import { verifyToken } from 'chanjs/helper/index.js';
288
-
289
- // 示例:验证令牌
290
- const token = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...';
291
- try {
292
- const payload = verifyToken(token); // 内部已配置密钥
293
- console.log(payload); // 令牌解析后的载荷,如 { userId: 1, exp: 1716300000 }
294
- } catch (err) {
295
- console.error('令牌无效:', err.message);
296
- }
297
- ```
298
- **参数说明**:
299
- - `token` (String):JWT令牌字符串
300
- - 返回值:Object,令牌载荷(验证失败抛出异常)
193
+ ### 参数校验中间件
301
194
 
302
- ### 2. generateToken
303
- **功能**:生成JWT令牌
304
- **调用方式**:
305
195
  ```javascript
306
- import { generateToken } from 'chanjs/helper/index.js';
196
+ import { validate, validateAll } from 'chanjs';
197
+ import { z } from 'zod';
307
198
 
308
- // 示例:生成令牌(有效期1小时)
309
- const payload = { userId: 1, username: '张三' };
310
- const token = generateToken(payload, 3600); // 过期时间3600秒
311
- console.log(token); // 生成的JWT字符串
312
- ```
313
- **参数说明**:
314
- - `payload` (Object):令牌载荷(需包含非敏感信息)
315
- - `expire` (Number):过期时间(秒),默认3600
316
- - 返回值:String,JWT令牌
317
-
318
- ### 3. setToken
319
- **功能**:设置令牌到响应头/客户端存储(如Cookie)
320
- **调用方式**:
321
- ```javascript
322
- import { setToken } from 'chanjs/helper/index.js';
323
- // 示例(Express框架)
324
- app.post('/login', (req, res) => {
325
- const token = generateToken({ userId: 1 });
326
- setToken(res, token); // 将令牌设置到Cookie/响应头
327
- res.send({ code: 200, msg: '登录成功' });
328
- });
329
- ```
330
- **参数说明**:
331
- - `res` (Object):HTTP响应对象(Express/Koa的res)
332
- - `token` (String):JWT令牌
333
- - 返回值:无
334
-
335
- ### 4. getToken
336
- **功能**:从请求中获取JWT令牌(从Header/Cookie)
337
- **调用方式**:
338
- ```javascript
339
- import { getToken } from 'chanjs/helper/index.js';
340
- // 示例(Express框架)
341
- app.get('/profile', (req, res) => {
342
- const token = getToken(req); // 从Authorization头/Cookie获取
343
- if (!token) {
344
- return res.send({ code: 401, msg: '未登录' });
345
- }
346
- // 验证令牌...
347
- });
348
- ```
349
- **参数说明**:
350
- - `req` (Object):HTTP请求对象(Express/Koa的req)
351
- - 返回值:String/null,获取到的令牌(无则返回null)
352
-
353
- ## 八、签名/加密(sign.js)
354
- ### 1. signData
355
- **功能**:对数据进行签名(防止篡改)
356
- **调用方式**:
357
- ```javascript
358
- import { signData } from 'chanjs/helper/index.js';
199
+ // 单源校验
200
+ router.post('/user', validate('body', z.object({
201
+ name: z.string().min(1),
202
+ age: z.number().int().positive()
203
+ })), ctrl.create);
359
204
 
360
- // 示例:对数据签名
361
- const data = { userId: 1, amount: 100 };
362
- const sign = signData(data, 'your-secret-key'); // 传入数据和密钥
363
- console.log(sign); // 生成的签名字符串
205
+ // 多源校验
206
+ router.post('/user', validateAll({
207
+ body: z.object({ name: z.string() }),
208
+ query: z.object({ page: z.coerce.number() })
209
+ }), ctrl.create);
364
210
  ```
365
- **参数说明**:
366
- - `data` (Object):待签名的数据
367
- - `secret` (String):签名密钥(内部可配置默认密钥)
368
- - 返回值:String,签名字符串
369
-
370
- ### 2. verifySign
371
- **功能**:验证数据签名的有效性
372
- **调用方式**:
373
- ```javascript
374
- import { verifySign } from 'chanjs/helper/index.js';
375
211
 
376
- // 示例:验证签名
377
- const data = { userId: 1, amount: 100 };
378
- const sign = 'xxx...'; // 前端传入的签名
379
- const isValid = verifySign(data, sign, 'your-secret-key');
380
- console.log(isValid); // true(签名有效)/false(无效)
381
- ```
382
- **参数说明**:
383
- - `data` (Object):原始数据
384
- - `sign` (String):待验证的签名
385
- - `secret` (String):签名密钥(需与签名时一致)
386
- - 返回值:Boolean,签名是否有效
387
-
388
- ### 3. aesEncrypt
389
- **功能**:AES加密数据
390
- **调用方式**:
212
+ ### XSS 过滤
213
+
391
214
  ```javascript
392
- import { aesEncrypt } from 'chanjs/helper/index.js';
215
+ import { filterXSS } from 'chanjs';
393
216
 
394
- // 示例:加密字符串
395
- const rawData = '敏感信息:123456';
396
- const encrypted = aesEncrypt(rawData, 'aes-secret-key', 'aes-iv'); // 密钥+向量
397
- console.log(encrypted); // 加密后的Base64字符串
217
+ const safe = filterXSS('<script>alert("xss")</script>');
218
+ // 支持字符串、对象、数组递归过滤
398
219
  ```
399
- **参数说明**:
400
- - `data` (String):待加密数据
401
- - `key` (String):AES密钥(内部可配置默认)
402
- - `iv` (String):AES向量(内部可配置默认)
403
- - 返回值:String,加密后的Base64字符串
404
-
405
- ### 4. aesDecrypt
406
- **功能**:AES解密数据
407
- **调用方式**:
220
+
221
+ ### 关键词检测
222
+
408
223
  ```javascript
409
- import { aesDecrypt } from 'chanjs/helper/index.js';
224
+ import { checkKeywords } from 'chanjs';
410
225
 
411
- // 示例:解密
412
- const encrypted = 'xxx...'; // 加密后的字符串
413
- const decrypted = aesDecrypt(encrypted, 'aes-secret-key', 'aes-iv');
414
- console.log(decrypted); // 原始敏感信息:123456
226
+ const result = checkKeywords('SELECT * FROM users');
227
+ // null { category: 'sqlInjection', keyword: 'SELECT' }
415
228
  ```
416
- **参数说明**:
417
- - `data` (String):加密后的Base64字符串
418
- - `key` (String):AES密钥(需与加密时一致)
419
- - `iv` (String):AES向量(需与加密时一致)
420
- - 返回值:String,解密后的原始数据
421
-
422
- ## 九、网络请求(request.js)
423
- ### 1. request
424
- **功能**:封装的HTTP请求方法(支持GET/POST等)
425
- **调用方式**:
229
+
230
+ ### 限流中间件
231
+
426
232
  ```javascript
427
- import { request } from 'chanjs/helper/index.js';
428
-
429
- // 示例1:GET请求
430
- request({
431
- url: 'https://api.example.com/user',
432
- method: 'GET',
433
- params: { id: 1 } // URL参数
434
- }).then(res => {
435
- console.log(res); // 响应数据
436
- }).catch(err => {
437
- console.error(err);
438
- });
233
+ import { createRateLimitMiddleware } from 'chanjs';
439
234
 
440
- // 示例2:POST请求(JSON数据)
441
- request({
442
- url: 'https://api.example.com/user',
443
- method: 'POST',
444
- data: { name: '张三', age: 20 }, // 请求体
445
- headers: { 'Content-Type': 'application/json' }
446
- }).then(res => {
447
- console.log(res);
235
+ const rateLimit = createRateLimitMiddleware({
236
+ windowMs: '1m', // 时间窗口,支持 '1s'/'1m'/'1h'/'1d' 格式
237
+ max: 100, // 窗口内最大请求数
238
+ ignorePaths: ['/api/public'] // 忽略路径
448
239
  });
449
240
  ```
450
- **参数说明**:
451
- - `options` (Object):请求配置
452
- - `url` (String):请求地址(必传)
453
- - `method` (String):请求方法,默认GET
454
- - `params` (Object):URL查询参数
455
- - `data` (Object/String):请求体数据
456
- - `headers` (Object):请求头
457
- - `timeout` (Number):超时时间(毫秒),默认5000
458
- - 返回值:Promise,解析后为响应数据
459
-
460
- ## 十、数据解析(data-parse.js)
461
- ### 1. dataParse
462
- **功能**:通用数据解析(如表单数据/JSON字符串转对象)
463
- **调用方式**:
464
- ```javascript
465
- import { dataParse } from 'chanjs/helper/index.js';
466
241
 
467
- // 示例1:解析JSON字符串
468
- const jsonStr = '{"name":"张三","age":20}';
469
- const obj1 = dataParse(jsonStr, 'json');
470
- console.log(obj1); // { name: '张三', age: 20 }
242
+ ## 存储层
471
243
 
472
- // 示例2:解析表单字符串
473
- const formStr = 'name=张三&age=20';
474
- const obj2 = dataParse(formStr, 'form');
475
- console.log(obj2); // { name: '张三', age: '20' }
476
- ```
477
- **参数说明**:
478
- - `data` (String):待解析的数据
479
- - `type` (String):解析类型,可选 `json`/`form`,默认`json`
480
- - 返回值:Object,解析后的对象
481
-
482
- ### 2. arrToObj
483
- **功能**:将数组转为对象(指定key为属性名)
484
- **调用方式**:
485
- ```javascript
486
- import { arrToObj } from 'chanjs/helper/index.js';
244
+ ### cache - 内存缓存
487
245
 
488
- // 示例:将用户数组转为以id为key的对象
489
- const userArr = [{ id: 1, name: '张三' }, { id: 2, name: '李四' }];
490
- const userObj = arrToObj(userArr, 'id');
491
- console.log(userObj);
492
- // { 1: { id: 1, name: '张三' }, 2: { id: 2, name: '李四' } }
493
- ```
494
- **参数说明**:
495
- - `arr` (Array):源数组
496
- - `key` (String):作为对象属性名的字段
497
- - 返回值:Object,转换后的对象
498
-
499
- ### 3. parseJsonFields
500
- **功能**:解析对象中的JSON字符串字段为对象
501
- **调用方式**:
502
246
  ```javascript
503
- import { parseJsonFields } from 'chanjs/helper/index.js';
504
-
505
- // 示例:解析userInfo字段(JSON字符串)
506
- const data = {
507
- id: 1,
508
- userInfo: '{"name":"张三","age":20}'
509
- };
510
- const parsedData = parseJsonFields(data, ['userInfo']);
511
- console.log(parsedData.userInfo); // { name: '张三', age: 20 }
512
- ```
513
- **参数说明**:
514
- - `obj` (Object):源对象
515
- - `fields` (Array):需要解析的字段名数组
516
- - 返回值:Object,解析后的新对象
517
-
518
- ### 4. buildTree
519
- **功能**:将扁平数组转为树形结构(如分类/菜单)
520
- **调用方式**:
521
- ```javascript
522
- import { buildTree } from 'chanjs/helper/index.js';
523
-
524
- // 示例:构建菜单树
525
- const menuArr = [
526
- { id: 1, name: '系统管理', parentId: 0 },
527
- { id: 2, name: '用户管理', parentId: 1 },
528
- { id: 3, name: '角色管理', parentId: 1 }
529
- ];
530
- const menuTree = buildTree(menuArr, 'id', 'parentId', 'children');
531
- console.log(menuTree);
532
- // 输出:[{ id: 1, name: '系统管理', parentId: 0, children: [{ id: 2, ... }, { id: 3, ... }] }]
533
- ```
534
- **参数说明**:
535
- - `arr` (Array):扁平数组
536
- - `idKey` (String):ID字段名,默认'id'
537
- - `parentKey` (String):父ID字段名,默认'parentId'
538
- - `childrenKey` (String):子节点字段名,默认'children'
539
- - 返回值:Array,树形结构数组
540
-
541
- ## 十一、树形结构(tree.js)
542
- ### 1. tree
543
- **功能**:通用树形结构生成(简化版buildTree)
544
- **调用方式**:
545
- ```javascript
546
- import { tree } from 'chanjs/helper/index.js';
547
-
548
- // 示例:生成分类树
549
- const cateArr = [
550
- { id: 1, name: '电子产品', parentId: 0 },
551
- { id: 2, name: '手机', parentId: 1 }
552
- ];
553
- const cateTree = tree(cateArr);
554
- console.log(cateTree); // 树形结构数组
247
+ import { cache } from 'chanjs';
248
+
249
+ cache.set('key', value, 60000); // 设置,TTL 毫秒
250
+ cache.get('key'); // 读取
251
+ cache.has('key'); // 检查存在
252
+ cache.del('key'); // 删除
253
+ cache.clear(); // 清空
254
+ cache.size(); // 获取数量
255
+ cache.incr('key', 60000); // 自增(限流专用)
256
+ cache.incrAndExpire('key', 60000); // 自增并设置过期时间
257
+ cache.expire('key', 30000); // 刷新过期时间
555
258
  ```
556
- **参数说明**:
557
- - `arr` (Array):扁平数组(默认id/parentId字段)
558
- - 返回值:Array,树形结构数组
559
259
 
560
- ### 2. treeById
561
- **功能**:根据ID查找树形结构中的节点
562
- **调用方式**:
563
- ```javascript
564
- import { treeById } from 'chanjs/helper/index.js';
260
+ ### store - 统一存储适配层
565
261
 
566
- // 示例:查找ID为2的节点
567
- const cateTree = [/* 树形结构数组 */];
568
- const node = treeById(cateTree, 2);
569
- console.log(node); // { id: 2, name: '手机', parentId: 1 }
570
- ```
571
- **参数说明**:
572
- - `tree` (Array):树形结构数组
573
- - `id` (Number/String):节点ID
574
- - 返回值:Object/null,找到的节点(无则返回null)
575
-
576
- ## 十二、字段过滤(filter.js)
577
- ### 1. filterFields
578
- **功能**:过滤对象中的字段(保留/排除指定字段)
579
- **调用方式**:
580
262
  ```javascript
581
- import { filterFields } from 'chanjs/helper/index.js';
263
+ import { store } from 'chanjs';
582
264
 
583
- // 示例1:保留指定字段
584
- const user = { id: 1, name: '张三', password: '123456', age: 20 };
585
- const userSafe = filterFields(user, ['id', 'name', 'age'], 'keep');
586
- console.log(userSafe); // { id: 1, name: '张三', age: 20 }
265
+ // 初始化(框架自动调用)
266
+ await store.init({ REDIS_ENABLED: false, REDIS: {} });
587
267
 
588
- // 示例2:排除指定字段
589
- const userNoPwd = filterFields(user, ['password'], 'exclude');
590
- console.log(userNoPwd); // { id: 1, name: '张三', age: 20 }
591
- ```
592
- **参数说明**:
593
- - `obj` (Object):源对象
594
- - `fields` (Array):字段名数组
595
- - `mode` (String):过滤模式,`keep`(保留)/`exclude`(排除),默认'keep'
596
- - 返回值:Object,过滤后的新对象
597
-
598
- ## 十三、响应格式化(response.js)
599
- ### 1. success
600
- **功能**:生成成功响应格式
601
- **调用方式**:
602
- ```javascript
603
- import { success } from 'chanjs/helper/index.js';
268
+ // 统一 API(自动切换内存/Redis)
269
+ await store.get('key');
270
+ await store.set('key', value, 60000);
271
+ await store.del('key');
272
+ await store.incr('key');
273
+ await store.incrAndExpire('key', 60000);
274
+ await store.exists('key');
275
+ await store.expire('key', 30000);
604
276
 
605
- // 示例:返回成功响应
606
- const resData = success({ data: { list: [1,2,3] }, msg: '操作成功' });
607
- console.log(resData);
608
- // 输出:{ code: 200, msg: '操作成功', data: { list: [1,2,3] } }
277
+ // 诊断信息
278
+ store.getInfo();
279
+ // { mode: 'memory' | 'redis', memorySize, redisConnected, circuitOpen }
280
+
281
+ // 释放资源
282
+ await store.close();
609
283
  ```
610
- **参数说明**:
611
- - `options` (Object):
612
- - `data` (Any):响应数据,默认{}
613
- - `msg` (String):提示信息,默认'操作成功'
614
- - `code` (Number):状态码,默认200
615
- - 返回值:Object,成功响应对象
616
-
617
- ### 2. fail
618
- **功能**:生成失败响应格式
619
- **调用方式**:
284
+
285
+ ## 工具模块
286
+
287
+ ### helper 聚合对象
288
+
620
289
  ```javascript
621
- import { fail } from 'chanjs/helper/index.js';
290
+ import { helper } from 'chanjs';
622
291
 
623
- // 示例:返回失败响应
624
- const resData = fail({ msg: '参数错误', code: 400 });
625
- console.log(resData);
626
- // 输出:{ code: 400, msg: '参数错误', data: {} }
292
+ const {
293
+ formatDateFields,
294
+ delImg, readFileContent, saveFileContent, getFolders, getHtmlFilesSync,
295
+ htmlEncode, htmlDecode, escapeScript, filterImgFromStr,
296
+ getIp,
297
+ request,
298
+ arrToObj, getChildrenId,
299
+ tree, treeById,
300
+ filterFields,
301
+ pages,
302
+ cache, store,
303
+ setToken, getToken,
304
+ aesEncrypt, aesDecrypt,
305
+ success, fail,
306
+ createRateLimitMiddleware,
307
+ filterXSS, checkKeywords
308
+ } = helper;
627
309
  ```
628
- **参数说明**:
629
- - `options` (Object):
630
- - `msg` (String):错误提示,默认'操作失败'
631
- - `data` (Any):附加数据,默认{}
632
- - `code` (Number):错误码,默认201
633
- - 返回值:Object,失败响应对象
634
-
635
- ### 3. error
636
- **功能**:生成服务器错误响应格式
637
- **调用方式**:
310
+
311
+ ### loader 命名空间
312
+
638
313
  ```javascript
639
- import { error } from 'chanjs/helper/index.js';
314
+ import { loader } from 'chanjs';
640
315
 
641
- // 示例:返回服务器错误响应
642
- const resData = error({ msg: '数据库查询失败' });
643
- console.log(resData);
644
- // 输出:{ code: 500, msg: '数据库查询失败', data: {} }
316
+ // 加载模块路由
317
+ await loader.loadModuleRouter(chan);
318
+
319
+ // 加载公共路由
320
+ await loader.loadCommonRouter(chan);
645
321
  ```
646
- **参数说明**:
647
- - `options` (Object):
648
- - `msg` (String):错误提示,默认'服务器内部错误'
649
- - `data` (Any):附加数据,默认{}
650
- - 返回值:Object,错误响应对象(默认code=500)
651
-
652
- ### 4. parseDatabaseError
653
- **功能**:解析数据库错误信息(格式化报错)
654
- **调用方式**:
322
+
323
+ ### utils 命名空间
324
+
655
325
  ```javascript
656
- import { parseDatabaseError } from 'chanjs/helper/index.js';
657
-
658
- // 示例:解析数据库异常
659
- try {
660
- // 数据库操作...
661
- } catch (err) {
662
- const errInfo = parseDatabaseError(err);
663
- console.log(errInfo); // { msg: '主键冲突', code: 'ER_DUP_ENTRY' }
664
- }
326
+ import { utils } from 'chanjs';
327
+ // 包含 helper 中的所有工具函数
665
328
  ```
666
- **参数说明**:
667
- - `err` (Error):数据库抛出的异常对象
668
- - 返回值:Object,解析后的错误信息(msg/code)
669
329
 
670
- ### 5. notFoundResponse
671
- **功能**:生成404响应格式
672
- **调用方式**:
673
- ```javascript
674
- import { notFoundResponse } from 'chanjs/helper/index.js';
330
+ ## 日志
675
331
 
676
- // 示例:返回404响应
677
- const resData = notFoundResponse({ msg: '资源不存在' });
678
- console.log(resData);
679
- // 输出:{ code: 404, msg: '资源不存在', data: {} }
680
- ```
681
- **参数说明**:
682
- - `options` (Object):
683
- - `msg` (String):提示信息,默认'请求资源不存在'
684
- - 返回值:Object,404响应对象
685
-
686
- ### 6. errorResponse
687
- **功能**:通用错误响应生成(自定义码和信息)
688
- **调用方式**:
689
332
  ```javascript
690
- import { errorResponse } from 'chanjs/helper/index.js';
333
+ import { logger, createLogger } from 'chanjs';
691
334
 
692
- // 示例:生成自定义错误响应
693
- const resData = errorResponse(403, '无访问权限', { userId: 1 });
694
- console.log(resData);
695
- // 输出:{ code: 403, msg: '无访问权限', data: { userId: 1 } }
696
- ```
697
- **参数说明**:
698
- - `code` (Number):错误码
699
- - `msg` (String):错误提示
700
- - `data` (Any):附加数据,默认{}
701
- - 返回值:Object,自定义错误响应对象
702
-
703
- ## 十四、内容检查(checker.js)
704
- ### 1. checkKeywords
705
- **功能**:检查文本中是否包含敏感关键词
706
- **调用方式**:
707
- ```javascript
708
- import { checkKeywords } from 'chanjs/helper/index.js';
335
+ logger.info('信息日志');
336
+ logger.warn('警告日志');
337
+ logger.error('错误日志');
709
338
 
710
- // 示例:检查内容是否含敏感词
711
- const content = '这是一条包含敏感词的内容';
712
- const { isIllegal, keywords } = checkKeywords(content);
713
- console.log(isIllegal); // true(包含敏感词)/false
714
- console.log(keywords); // ['敏感词'](检测到的敏感词)
339
+ // 创建自定义 logger
340
+ const customLogger = createLogger('MyModule');
341
+ customLogger.info('自定义模块日志');
715
342
  ```
716
- **参数说明**:
717
- - `text` (String):待检查的文本
718
- - 返回值:Object,{ isIllegal: Boolean, keywords: Array }
719
343
 
720
- ### 2. isIgnored
721
- **功能**:检查内容是否属于忽略项(如白名单/过滤规则)
722
- **调用方式**:
723
- ```javascript
724
- import { isIgnored } from 'chanjs/helper/index.js';
344
+ ## 全局资源访问
725
345
 
726
- // 示例:检查用户ID是否在忽略列表
727
- const userId = 1;
728
- const isIgnore = isIgnored(userId, 'user_ignore_list'); // 指定忽略规则名称
729
- console.log(isIgnore); // true(忽略)/false(不忽略)
730
- ```
731
- **参数说明**:
732
- - `value` (Any):待检查的值
733
- - `rule` (String):忽略规则名称(内部配置的规则标识)
734
- - 返回值:Boolean,是否忽略
735
-
736
- ## 十五、XSS过滤(xss-filter.js)
737
- ### 1. filterXSS
738
- **功能**:过滤文本中的XSS攻击脚本
739
- **调用方式**:
740
- ```javascript
741
- import { filterXSS } from 'chanjs/helper/index.js';
346
+ Controller、Service、Repository 继承自 Container,可访问:
742
347
 
743
- // 示例:过滤XSS脚本
744
- const unsafeText = '<script>alert("xss")</script> <div>正常内容</div>';
745
- const safeText = filterXSS(unsafeText);
746
- console.log(safeText); // &lt;script&gt;alert("xss")&lt;/script&gt; <div>正常内容</div>
747
- ```
748
- **参数说明**:
749
- - `text` (String):待过滤的文本
750
- - 返回值:String,过滤后的安全文本
751
-
752
- ## 十六、限流中间件(rate-limit.js)
753
- ### 1. createRateLimitMiddleware
754
- **功能**:创建接口限流中间件(防止高频请求)
755
- **调用方式**:
756
- ```javascript
757
- import { createRateLimitMiddleware } from 'chanjs/helper/index.js';
758
- import express from 'express';
759
- const app = express();
348
+ | 属性 | 说明 |
349
+ |------|------|
350
+ | `this.app` | 全局应用实例 |
351
+ | `this.config` | 全局配置对象 |
352
+ | `this.db` | 默认数据库连接 |
353
+ | `this.paths` | 路径工具对象 |
354
+ | `this.get(moduleName, fileName)` | 动态加载组件 |
760
355
 
761
- // 示例:创建限流中间件(每分钟最多100次请求)
762
- const rateLimit = createRateLimitMiddleware({
763
- windowMs: 60 * 1000, // 时间窗口(毫秒)
764
- max: 100, // 窗口内最大请求数
765
- message: { code: 429, msg: '请求过于频繁,请稍后再试' }
766
- });
356
+ ## 错误码规范
767
357
 
768
- // 应用到所有接口
769
- app.use(rateLimit);
358
+ | 范围 | 说明 |
359
+ |------|------|
360
+ | 0 | 成功 |
361
+ | 1xxx | 通用业务错误 |
362
+ | 5xxx | 系统错误 |
363
+ | 6xxx | 数据库错误 |
364
+
365
+ 详见 [Common.md](./Common.md) 中的完整错误码列表。
366
+
367
+ ## 目录结构
770
368
 
771
- // 或应用到单个接口
772
- app.get('/api/user', rateLimit, (req, res) => {
773
- res.send('用户信息');
774
- });
775
369
  ```
776
- **参数说明**:
777
- - `options` (Object):限流配置
778
- - `windowMs` (Number):时间窗口(毫秒),默认60000
779
- - `max` (Number):窗口内最大请求数,默认100
780
- - `message` (Object):限流提示响应,默认{ code: 429, msg: '请求频繁' }
781
- - `keyGenerator` (Function):生成限流标识的函数(默认取IP)
782
- - 返回值:Function,中间件函数(适配Express/Koa)
783
-
784
- ## 注意事项
785
- 1. 所有工具函数的默认配置(如密钥、超时时间等)可在对应子文件(如jwt.js、sign.js)中调整;
786
- 2. 涉及加密/签名的函数,建议使用项目自定义密钥,避免使用默认值;
787
- 3. 中间件类函数(如createRateLimitMiddleware)需适配对应Web框架(Express/Koa);
788
- 4. 文件操作函数需注意路径权限,避免因权限问题导致读写失败;
789
- 5. 所有异步函数(如request)返回Promise,需使用async/await或.then()处理。
370
+ app/
371
+ ├── modules/
372
+ │ ├── {moduleName}/
373
+ │ │ ├── controller/ # 控制器
374
+ │ │ ├── service/ # 服务层
375
+ │ │ ├── repository/ # 数据访问层
376
+ │ │ └── router.js # 模块路由
377
+ ├── config/
378
+ │ └── index.js # 全局配置
379
+ └── common/
380
+ └── router.js # 公共路由
381
+ ```
382
+
383
+ ## 相关文档
384
+
385
+ - [QuickStart](./QuickStart.md) - 快速入门
386
+ - [Controller](./Controller.md) - 控制器基类
387
+ - [Service](./Service.md) - 服务基类
388
+ - [Repository](./Repository.md) - 数据访问层
389
+ - [Cache](./Cache.md) - 缓存工具
390
+ - [Common](./Common.md) - 公共工具模块