chanjs 2.7.3 → 2.7.5
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/USAGE.md +533 -0
- package/config/index.js +37 -6
- package/core/App.js +166 -0
- package/core/Container.js +77 -0
- package/core/Controller.js +29 -0
- package/core/Database.js +93 -0
- package/core/Repository.js +327 -0
- package/core/Service.js +11 -0
- package/core/bootstrap/error-handler.js +104 -0
- package/core/bootstrap/hook-runner.js +64 -0
- package/core/bootstrap/middleware.js +35 -0
- package/core/bootstrap/router-loader.js +53 -0
- package/core/errors.js +224 -0
- package/core/loader.js +89 -0
- package/core/registry.js +17 -0
- package/doc/Cache.md +279 -106
- package/doc/Common.md +590 -134
- package/doc/Controller.md +166 -95
- package/doc/Help.md +299 -698
- package/doc/QuickStart.md +116 -0
- package/doc/Repository.md +560 -0
- package/doc/Service.md +201 -527
- package/index.js +75 -37
- package/middleware/body.js +17 -0
- package/middleware/cookie.js +7 -15
- package/middleware/cors.js +9 -27
- package/middleware/favicon.js +7 -17
- package/middleware/header.js +15 -16
- package/middleware/index.js +11 -11
- package/middleware/log.js +26 -56
- package/middleware/static.js +15 -28
- package/middleware/template.js +75 -115
- package/middleware/validate.js +79 -0
- package/middleware/waf.js +174 -197
- package/package.json +11 -3
- package/response/code.js +73 -0
- package/response/index.js +9 -6
- package/response/response.js +82 -236
- package/security/checker.js +26 -74
- package/security/index.js +4 -9
- package/security/jwt.js +69 -142
- package/security/keywords.js +32 -136
- package/security/rate-limit.js +38 -80
- package/security/sign.js +83 -176
- package/security/xss-filter.js +21 -53
- package/storage/cache.js +57 -196
- package/storage/index.js +3 -6
- package/storage/redis.js +123 -181
- package/storage/store.js +163 -188
- package/utils/data-parse.js +42 -186
- package/utils/file.js +73 -244
- package/utils/filter.js +22 -25
- package/utils/html.js +49 -33
- package/utils/index.js +21 -7
- package/utils/ip.js +31 -71
- package/utils/logger.js +117 -0
- package/utils/pages.js +55 -0
- package/utils/paths.js +18 -0
- package/utils/request.js +94 -136
- package/utils/signal.js +87 -0
- package/utils/time.js +33 -75
- package/utils/tree.js +112 -104
- package/App.js +0 -533
- package/base/Aop.js +0 -195
- package/base/Container.js +0 -161
- package/base/Controller.js +0 -65
- package/base/Database.js +0 -133
- package/base/Event.js +0 -61
- package/base/Repository.js +0 -644
- package/common/api.js +0 -35
- package/common/code.js +0 -52
- package/common/email.js +0 -191
- package/common/index.js +0 -5
- package/common/pages.js +0 -120
- package/common/utils.js +0 -73
- package/config/code.js +0 -166
- package/config/paths.js +0 -60
- package/doc/Aop.md +0 -269
- package/doc/Email.md +0 -114
- package/doc/Event.md +0 -232
- package/global/env.js +0 -11
- package/global/import.js +0 -39
- package/global/index.js +0 -8
- package/helper/index.js +0 -79
- package/loader/index.js +0 -6
- package/loader/loader.js +0 -138
- package/middleware/compress.js +0 -185
- package/middleware/setBody.js +0 -32
- package/realtime/index.js +0 -7
- package/realtime/sse.js +0 -424
- package/realtime/websocket.js +0 -540
- package/schedule/index.js +0 -6
- package/schedule/schedule.js +0 -491
package/doc/Help.md
CHANGED
|
@@ -1,789 +1,390 @@
|
|
|
1
|
-
#
|
|
2
|
-
本文档详细说明 `chanjs/helper/index.js` 导出的所有工具函数的调用方式、参数说明及使用示例,帮助开发者快速集成和使用这些工具。
|
|
1
|
+
# ChanJS 框架 API 参考
|
|
3
2
|
|
|
4
|
-
##
|
|
5
|
-
### 1. loaderSort
|
|
6
|
-
**功能**:对加载的模块/配置进行排序处理
|
|
7
|
-
**调用方式**:
|
|
8
|
-
```javascript
|
|
9
|
-
import { loaderSort } from 'chanjs/helper/index.js';
|
|
3
|
+
## 概述
|
|
10
4
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
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
|
|
10
|
+
import Chan from 'chanjs'; // 默认导出:应用主类
|
|
25
11
|
|
|
26
|
-
//
|
|
27
|
-
|
|
28
|
-
|
|
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
|
-
|
|
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
|
-
|
|
51
|
-
|
|
52
|
-
|
|
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
|
-
|
|
68
|
-
|
|
69
|
-
|
|
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
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
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
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
**功能**:缓存操作类(支持设置、获取、删除缓存等)
|
|
104
|
-
**调用方式**:
|
|
56
|
+
|
|
57
|
+
| 方法 | 说明 |
|
|
58
|
+
|------|------|
|
|
59
|
+
| `success({ data, msg })` | 成功响应,默认 code=0 |
|
|
60
|
+
| `fail(opts)` | 失败响应,支持字符串简写或对象配置,默认 code=1008 |
|
|
61
|
+
|
|
62
|
+
### Repository - 数据访问基类
|
|
63
|
+
|
|
105
64
|
```javascript
|
|
106
|
-
|
|
65
|
+
class UserRepo extends Repository {
|
|
66
|
+
constructor() {
|
|
67
|
+
super('users'); // 表名
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
```
|
|
107
71
|
|
|
108
|
-
|
|
109
|
-
|
|
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
|
-
|
|
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
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
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
|
-
|
|
131
|
+
// 字符串简写
|
|
132
|
+
throw new NotFoundError('用户不存在');
|
|
133
|
+
|
|
134
|
+
// 对象配置
|
|
135
|
+
throw new ValidationError({
|
|
136
|
+
msg: '参数校验失败',
|
|
137
|
+
fields: ['name', 'email']
|
|
138
|
+
});
|
|
151
139
|
|
|
152
|
-
//
|
|
153
|
-
|
|
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
|
-
###
|
|
162
|
-
**功能**:生成指定目录的文件树结构(递归遍历)
|
|
163
|
-
**调用方式**:
|
|
164
|
-
```javascript
|
|
165
|
-
import { getFileTree } from 'chanjs/helper/index.js';
|
|
144
|
+
### 错误工具函数
|
|
166
145
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
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
|
-
|
|
177
|
-
**功能**:读取文件内容(支持文本/JSON格式)
|
|
178
|
-
**调用方式**:
|
|
179
|
-
```javascript
|
|
180
|
-
import { readFileContent } from 'chanjs/helper/index.js';
|
|
154
|
+
## 响应工具
|
|
181
155
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
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 {
|
|
170
|
+
import { setToken, getToken, verifyToken } from 'chanjs';
|
|
200
171
|
|
|
201
|
-
//
|
|
202
|
-
|
|
172
|
+
// 签发令牌
|
|
173
|
+
const token = setToken({ userId: 1 }, secretKey, '7d');
|
|
203
174
|
|
|
204
|
-
//
|
|
205
|
-
|
|
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
|
-
//
|
|
208
|
-
|
|
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
|
-
|
|
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 {
|
|
187
|
+
import { aesEncrypt, aesDecrypt } from 'chanjs';
|
|
240
188
|
|
|
241
|
-
|
|
242
|
-
const
|
|
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
|
-
|
|
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 {
|
|
196
|
+
import { validate, validateAll } from 'chanjs';
|
|
197
|
+
import { z } from 'zod';
|
|
307
198
|
|
|
308
|
-
//
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
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
|
-
|
|
362
|
-
|
|
363
|
-
|
|
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
|
-
|
|
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 {
|
|
215
|
+
import { filterXSS } from 'chanjs';
|
|
393
216
|
|
|
394
|
-
|
|
395
|
-
|
|
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
|
-
|
|
401
|
-
|
|
402
|
-
- `iv` (String):AES向量(内部可配置默认)
|
|
403
|
-
- 返回值:String,加密后的Base64字符串
|
|
404
|
-
|
|
405
|
-
### 4. aesDecrypt
|
|
406
|
-
**功能**:AES解密数据
|
|
407
|
-
**调用方式**:
|
|
220
|
+
|
|
221
|
+
### 关键词检测
|
|
222
|
+
|
|
408
223
|
```javascript
|
|
409
|
-
import {
|
|
224
|
+
import { checkKeywords } from 'chanjs';
|
|
410
225
|
|
|
411
|
-
|
|
412
|
-
|
|
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
|
-
|
|
418
|
-
|
|
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 {
|
|
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
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
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
|
-
|
|
468
|
-
const jsonStr = '{"name":"张三","age":20}';
|
|
469
|
-
const obj1 = dataParse(jsonStr, 'json');
|
|
470
|
-
console.log(obj1); // { name: '张三', age: 20 }
|
|
242
|
+
## 存储层
|
|
471
243
|
|
|
472
|
-
|
|
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 {
|
|
504
|
-
|
|
505
|
-
//
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
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
|
-
###
|
|
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 {
|
|
263
|
+
import { store } from 'chanjs';
|
|
582
264
|
|
|
583
|
-
//
|
|
584
|
-
|
|
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
|
-
//
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
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
|
-
|
|
607
|
-
|
|
608
|
-
|
|
277
|
+
// 诊断信息
|
|
278
|
+
store.getInfo();
|
|
279
|
+
// { mode: 'memory' | 'redis', memorySize, redisConnected, circuitOpen }
|
|
280
|
+
|
|
281
|
+
// 释放资源
|
|
282
|
+
await store.close();
|
|
609
283
|
```
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
- 返回值:Object,成功响应对象
|
|
616
|
-
|
|
617
|
-
### 2. fail
|
|
618
|
-
**功能**:生成失败响应格式
|
|
619
|
-
**调用方式**:
|
|
284
|
+
|
|
285
|
+
## 工具模块
|
|
286
|
+
|
|
287
|
+
### helper 聚合对象
|
|
288
|
+
|
|
620
289
|
```javascript
|
|
621
|
-
import {
|
|
290
|
+
import { helper } from 'chanjs';
|
|
622
291
|
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
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
|
-
|
|
630
|
-
|
|
631
|
-
- `data` (Any):附加数据,默认{}
|
|
632
|
-
- `code` (Number):错误码,默认201
|
|
633
|
-
- 返回值:Object,失败响应对象
|
|
634
|
-
|
|
635
|
-
### 3. error
|
|
636
|
-
**功能**:生成服务器错误响应格式
|
|
637
|
-
**调用方式**:
|
|
310
|
+
|
|
311
|
+
### loader 命名空间
|
|
312
|
+
|
|
638
313
|
```javascript
|
|
639
|
-
import {
|
|
314
|
+
import { loader } from 'chanjs';
|
|
640
315
|
|
|
641
|
-
//
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
//
|
|
316
|
+
// 加载模块路由
|
|
317
|
+
await loader.loadModuleRouter(chan);
|
|
318
|
+
|
|
319
|
+
// 加载公共路由
|
|
320
|
+
await loader.loadCommonRouter(chan);
|
|
645
321
|
```
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
- `data` (Any):附加数据,默认{}
|
|
650
|
-
- 返回值:Object,错误响应对象(默认code=500)
|
|
651
|
-
|
|
652
|
-
### 4. parseDatabaseError
|
|
653
|
-
**功能**:解析数据库错误信息(格式化报错)
|
|
654
|
-
**调用方式**:
|
|
322
|
+
|
|
323
|
+
### utils 命名空间
|
|
324
|
+
|
|
655
325
|
```javascript
|
|
656
|
-
import {
|
|
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
|
-
|
|
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 {
|
|
333
|
+
import { logger, createLogger } from 'chanjs';
|
|
691
334
|
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
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
|
|
712
|
-
|
|
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
|
-
|
|
721
|
-
**功能**:检查内容是否属于忽略项(如白名单/过滤规则)
|
|
722
|
-
**调用方式**:
|
|
723
|
-
```javascript
|
|
724
|
-
import { isIgnored } from 'chanjs/helper/index.js';
|
|
344
|
+
## 全局资源访问
|
|
725
345
|
|
|
726
|
-
|
|
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
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
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
|
-
|
|
762
|
-
const rateLimit = createRateLimitMiddleware({
|
|
763
|
-
windowMs: 60 * 1000, // 时间窗口(毫秒)
|
|
764
|
-
max: 100, // 窗口内最大请求数
|
|
765
|
-
message: { code: 429, msg: '请求过于频繁,请稍后再试' }
|
|
766
|
-
});
|
|
356
|
+
## 错误码规范
|
|
767
357
|
|
|
768
|
-
|
|
769
|
-
|
|
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
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
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) - 公共工具模块
|