chanjs 2.7.8 → 2.7.11
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 +261 -363
- package/config/index.js +4 -2
- package/core/App.js +35 -0
- package/core/Container.js +56 -29
- package/core/Database.js +58 -8
- package/core/EventBus.js +88 -0
- package/core/Lang.js +56 -0
- package/core/Repository.js +34 -2
- package/core/Task.js +87 -0
- package/core/errors.js +0 -5
- package/doc/00-README.md +208 -0
- package/doc/01-/346/240/270/345/277/203/347/261/273Controller-Service-Repository.md +432 -0
- package/doc/02-/345/223/215/345/272/224/344/270/216/351/224/231/350/257/257.md +255 -0
- package/doc/03-/345/256/211/345/205/250/346/250/241/345/235/227.md +264 -0
- package/doc/04-/345/255/230/345/202/250/344/270/216/347/274/223/345/255/230.md +157 -0
- package/doc/05-/345/267/245/345/205/267/344/270/216/346/240/241/351/252/214.md +309 -0
- package/doc/06-/345/272/224/347/224/250/347/224/237/345/221/275/345/221/250/346/234/237.md +207 -0
- package/doc/07-/344/272/213/344/273/266/347/263/273/347/273/237EventBus.md +324 -0
- package/doc/08-/345/256/232/346/227/266/344/273/273/345/212/241Task.md +262 -0
- package/doc/09-/345/233/275/351/231/205/345/214/226Lang.md +220 -0
- package/index.js +30 -1
- package/middleware/log.js +48 -31
- package/middleware/waf.js +22 -90
- package/package.json +20 -2
- package/response/code.js +0 -12
- package/response/response.js +8 -2
- package/security/checker.js +14 -7
- package/security/keywords.js +2 -3
- package/utils/logger.js +60 -91
- package/utils/pages.js +13 -12
- package/utils/signal.js +21 -2
- package/USAGE.md +0 -533
- package/doc/Cache.md +0 -333
- package/doc/Common.md +0 -638
- package/doc/Controller.md +0 -223
- package/doc/Help.md +0 -390
- package/doc/QuickStart.md +0 -116
- package/doc/Repository.md +0 -560
- package/doc/Service.md +0 -240
- package/publish.bat +0 -4
- package/todo.md +0 -1
package/doc/Controller.md
DELETED
|
@@ -1,223 +0,0 @@
|
|
|
1
|
-
# Controller 控制器基类
|
|
2
|
-
|
|
3
|
-
## 概述
|
|
4
|
-
|
|
5
|
-
`Controller` 是所有业务控制器的基类,继承自 `Container` 容器类,提供统一的响应格式封装(成功/失败响应),规范控制器层的返回数据结构。
|
|
6
|
-
|
|
7
|
-
## 继承关系
|
|
8
|
-
|
|
9
|
-
```
|
|
10
|
-
Container <── Controller
|
|
11
|
-
```
|
|
12
|
-
|
|
13
|
-
## 构造函数
|
|
14
|
-
|
|
15
|
-
```javascript
|
|
16
|
-
constructor()
|
|
17
|
-
```
|
|
18
|
-
|
|
19
|
-
调用父类 `Container` 构造函数,指定组件类型为 `'controller'`。
|
|
20
|
-
|
|
21
|
-
## 核心方法
|
|
22
|
-
|
|
23
|
-
### 1. success - 成功响应
|
|
24
|
-
|
|
25
|
-
封装标准化的成功响应格式。
|
|
26
|
-
|
|
27
|
-
**语法**
|
|
28
|
-
|
|
29
|
-
```javascript
|
|
30
|
-
success({ data, msg = "操作成功" } = {})
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
**参数**
|
|
34
|
-
|
|
35
|
-
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|
|
36
|
-
|------|------|------|--------|------|
|
|
37
|
-
| data | any | 否 | {} | 响应数据 |
|
|
38
|
-
| msg | string | 否 | "操作成功" | 提示信息 |
|
|
39
|
-
|
|
40
|
-
**返回值**
|
|
41
|
-
|
|
42
|
-
```javascript
|
|
43
|
-
{
|
|
44
|
-
success: true,
|
|
45
|
-
code: 0,
|
|
46
|
-
msg: "操作成功",
|
|
47
|
-
data: { /* 响应数据 */ }
|
|
48
|
-
}
|
|
49
|
-
```
|
|
50
|
-
|
|
51
|
-
**示例**
|
|
52
|
-
|
|
53
|
-
```javascript
|
|
54
|
-
class UserController extends Controller {
|
|
55
|
-
async getUser(req, res) {
|
|
56
|
-
const user = { id: 1, name: "张三" };
|
|
57
|
-
return this.success({ data: user });
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
async createUser(req, res) {
|
|
61
|
-
// 业务逻辑...
|
|
62
|
-
return this.success({
|
|
63
|
-
data: { id: 100 },
|
|
64
|
-
msg: "创建成功"
|
|
65
|
-
});
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
```
|
|
69
|
-
|
|
70
|
-
### 2. fail - 失败响应
|
|
71
|
-
|
|
72
|
-
封装标准化的失败响应格式。
|
|
73
|
-
|
|
74
|
-
**语法**
|
|
75
|
-
|
|
76
|
-
```javascript
|
|
77
|
-
fail(opts = {})
|
|
78
|
-
```
|
|
79
|
-
|
|
80
|
-
**参数**
|
|
81
|
-
|
|
82
|
-
支持两种传参方式:
|
|
83
|
-
|
|
84
|
-
1. **字符串简写**:直接传入错误提示文案
|
|
85
|
-
2. **对象配置**:传入完整配置对象
|
|
86
|
-
|
|
87
|
-
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|
|
88
|
-
|------|------|------|--------|------|
|
|
89
|
-
| opts | string \| object | 否 | {} | 错误配置 |
|
|
90
|
-
| opts.msg | string | 否 | "操作失败" | 错误提示 |
|
|
91
|
-
| opts.code | number | 否 | 1008 | 错误码 |
|
|
92
|
-
| opts.data | any | 否 | {} | 附加数据 |
|
|
93
|
-
|
|
94
|
-
**返回值**
|
|
95
|
-
|
|
96
|
-
```javascript
|
|
97
|
-
{
|
|
98
|
-
success: false,
|
|
99
|
-
code: 1008, // 或其他错误码
|
|
100
|
-
msg: "操作失败",
|
|
101
|
-
data: {}
|
|
102
|
-
}
|
|
103
|
-
```
|
|
104
|
-
|
|
105
|
-
**示例**
|
|
106
|
-
|
|
107
|
-
```javascript
|
|
108
|
-
class UserController extends Controller {
|
|
109
|
-
async deleteUser(req, res) {
|
|
110
|
-
const { id } = req.params;
|
|
111
|
-
|
|
112
|
-
if (!id) {
|
|
113
|
-
// 字符串简写
|
|
114
|
-
return this.fail("用户ID不能为空");
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
if (id === 1) {
|
|
118
|
-
// 对象配置,自定义错误码
|
|
119
|
-
return this.fail({
|
|
120
|
-
msg: "该用户不可删除",
|
|
121
|
-
code: 1001,
|
|
122
|
-
data: { userId: id }
|
|
123
|
-
});
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
// 业务逻辑...
|
|
127
|
-
return this.success({ msg: "删除成功" });
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
```
|
|
131
|
-
|
|
132
|
-
## 完整示例
|
|
133
|
-
|
|
134
|
-
```javascript
|
|
135
|
-
import { Controller } from 'chanjs';
|
|
136
|
-
|
|
137
|
-
export default class UserController extends Controller {
|
|
138
|
-
constructor() {
|
|
139
|
-
super();
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
// 查询用户列表
|
|
143
|
-
async list(req, res) {
|
|
144
|
-
const users = [
|
|
145
|
-
{ id: 1, name: "张三" },
|
|
146
|
-
{ id: 2, name: "李四" }
|
|
147
|
-
];
|
|
148
|
-
return this.success({ data: users });
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
// 查询单个用户
|
|
152
|
-
async detail(req, res) {
|
|
153
|
-
const { id } = req.params;
|
|
154
|
-
const user = { id, name: "张三", age: 25 };
|
|
155
|
-
return this.success({ data: user });
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
// 创建用户
|
|
159
|
-
async create(req, res) {
|
|
160
|
-
const { name, email } = req.body;
|
|
161
|
-
|
|
162
|
-
if (!name || !email) {
|
|
163
|
-
return this.fail({
|
|
164
|
-
msg: "姓名和邮箱不能为空",
|
|
165
|
-
code: 1001
|
|
166
|
-
});
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
// 业务逻辑...
|
|
170
|
-
const newUser = { id: 100, name, email };
|
|
171
|
-
return this.success({
|
|
172
|
-
data: newUser,
|
|
173
|
-
msg: "创建成功"
|
|
174
|
-
});
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
// 更新用户
|
|
178
|
-
async update(req, res) {
|
|
179
|
-
const { id } = req.params;
|
|
180
|
-
const data = req.body;
|
|
181
|
-
|
|
182
|
-
// 业务逻辑...
|
|
183
|
-
return this.success({ msg: "更新成功" });
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
// 删除用户
|
|
187
|
-
async delete(req, res) {
|
|
188
|
-
const { id } = req.params;
|
|
189
|
-
|
|
190
|
-
if (!id) {
|
|
191
|
-
return this.fail("用户ID不能为空");
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
// 业务逻辑...
|
|
195
|
-
return this.success({ msg: "删除成功" });
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
```
|
|
199
|
-
|
|
200
|
-
## 错误码规范
|
|
201
|
-
|
|
202
|
-
| 错误码范围 | 说明 |
|
|
203
|
-
|-----------|------|
|
|
204
|
-
| 0 | 成功 |
|
|
205
|
-
| 1xxx | 业务错误 |
|
|
206
|
-
| 5xxx | 系统错误 |
|
|
207
|
-
| 6xxx | 数据库错误 |
|
|
208
|
-
|
|
209
|
-
常用错误码:
|
|
210
|
-
- `0` - 成功
|
|
211
|
-
- `1008` - 默认业务失败
|
|
212
|
-
- `400` - 参数错误
|
|
213
|
-
- `401` - 未授权
|
|
214
|
-
- `403` - 权限不足
|
|
215
|
-
- `404` - 资源不存在
|
|
216
|
-
- `500` - 系统内部错误
|
|
217
|
-
|
|
218
|
-
## 注意事项
|
|
219
|
-
|
|
220
|
-
1. 所有自定义控制器必须继承 `Controller` 基类
|
|
221
|
-
2. `success` 方法默认 code 为 `0`,`fail` 方法默认 code 为 `1008`
|
|
222
|
-
3. 响应结构统一为 `{ success, code, msg, data }`
|
|
223
|
-
4. 错误码建议与前端约定统一规范
|
package/doc/Help.md
DELETED
|
@@ -1,390 +0,0 @@
|
|
|
1
|
-
# ChanJS 框架 API 参考
|
|
2
|
-
|
|
3
|
-
## 概述
|
|
4
|
-
|
|
5
|
-
ChanJS 是基于 Express 5 的轻量级 Node.js MVC 框架,采用纯 JavaScript(ESM)编写。本文档汇总框架所有对外暴露的 API。
|
|
6
|
-
|
|
7
|
-
## 包入口
|
|
8
|
-
|
|
9
|
-
```javascript
|
|
10
|
-
import Chan from 'chanjs'; // 默认导出:应用主类
|
|
11
|
-
|
|
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';
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
## 核心类
|
|
31
|
-
|
|
32
|
-
### Chan - 应用主类
|
|
33
|
-
|
|
34
|
-
```javascript
|
|
35
|
-
const app = new Chan();
|
|
36
|
-
await app.start();
|
|
37
|
-
app.run(port => console.log(`监听端口 ${port}`));
|
|
38
|
-
```
|
|
39
|
-
|
|
40
|
-
| 方法 | 说明 |
|
|
41
|
-
|------|------|
|
|
42
|
-
| `start()` | 完整启动流程(配置→缓存→数据库→中间件→路由→错误处理→钩子) |
|
|
43
|
-
| `run(cb)` | 启动 HTTP 监听,`cb(port)` 回调接收端口号 |
|
|
44
|
-
| `beforeStart(fn)` | 注册启动前置钩子 |
|
|
45
|
-
| `shutdown()` | 执行优雅停机 |
|
|
46
|
-
|
|
47
|
-
### Controller - 控制器基类
|
|
48
|
-
|
|
49
|
-
```javascript
|
|
50
|
-
class UserController extends Controller {
|
|
51
|
-
async getUser(req, res) {
|
|
52
|
-
return this.success({ data: { id: 1 } });
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
```
|
|
56
|
-
|
|
57
|
-
| 方法 | 说明 |
|
|
58
|
-
|------|------|
|
|
59
|
-
| `success({ data, msg })` | 成功响应,默认 code=0 |
|
|
60
|
-
| `fail(opts)` | 失败响应,支持字符串简写或对象配置,默认 code=1008 |
|
|
61
|
-
|
|
62
|
-
### Repository - 数据访问基类
|
|
63
|
-
|
|
64
|
-
```javascript
|
|
65
|
-
class UserRepo extends Repository {
|
|
66
|
-
constructor() {
|
|
67
|
-
super('users'); // 表名
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
```
|
|
71
|
-
|
|
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
|
-
```
|
|
102
|
-
|
|
103
|
-
Service 是纯业务逻辑层,不包含 CRUD 方法。通过注入 Repository 实例进行数据操作。
|
|
104
|
-
|
|
105
|
-
## 错误体系
|
|
106
|
-
|
|
107
|
-
### 错误类
|
|
108
|
-
|
|
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 | 数据库操作超时 |
|
|
127
|
-
|
|
128
|
-
### 错误类使用
|
|
129
|
-
|
|
130
|
-
```javascript
|
|
131
|
-
// 字符串简写
|
|
132
|
-
throw new NotFoundError('用户不存在');
|
|
133
|
-
|
|
134
|
-
// 对象配置
|
|
135
|
-
throw new ValidationError({
|
|
136
|
-
msg: '参数校验失败',
|
|
137
|
-
fields: ['name', 'email']
|
|
138
|
-
});
|
|
139
|
-
|
|
140
|
-
// 带底层 cause
|
|
141
|
-
throw new SystemError('系统异常', originalError);
|
|
142
|
-
```
|
|
143
|
-
|
|
144
|
-
### 错误工具函数
|
|
145
|
-
|
|
146
|
-
| 函数 | 说明 |
|
|
147
|
-
|------|------|
|
|
148
|
-
| `isAppError(err)` | 判断是否为业务错误实例 |
|
|
149
|
-
| `describeError(err)` | 递归解析完整可读错误信息 |
|
|
150
|
-
| `errorExtraProps(err)` | 提取错误自定义附加属性 |
|
|
151
|
-
| `wrapDbError(err)` | 将数据库原生错误转换为 AppError 子类 |
|
|
152
|
-
| `parseStack(stack)` | 解析 V8 堆栈,提取报错文件和行号 |
|
|
153
|
-
|
|
154
|
-
## 响应工具
|
|
155
|
-
|
|
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
|
|
168
|
-
|
|
169
|
-
```javascript
|
|
170
|
-
import { setToken, getToken, verifyToken } from 'chanjs';
|
|
171
|
-
|
|
172
|
-
// 签发令牌
|
|
173
|
-
const token = setToken({ userId: 1 }, secretKey, '7d');
|
|
174
|
-
|
|
175
|
-
// 校验令牌(详细结果)
|
|
176
|
-
const result = await verifyToken(token, secretKey);
|
|
177
|
-
// { valid: true, reason: 'ok', payload: {...} }
|
|
178
|
-
// { valid: false, reason: 'expired' | 'invalid' | 'revoked' | 'missing' }
|
|
179
|
-
|
|
180
|
-
// 校验令牌(成功返回载荷,失败返回 null)
|
|
181
|
-
const payload = await getToken(token, secretKey);
|
|
182
|
-
```
|
|
183
|
-
|
|
184
|
-
### AES 加解密
|
|
185
|
-
|
|
186
|
-
```javascript
|
|
187
|
-
import { aesEncrypt, aesDecrypt } from 'chanjs';
|
|
188
|
-
|
|
189
|
-
const encrypted = await aesEncrypt('敏感数据', secretKey);
|
|
190
|
-
const decrypted = await aesDecrypt(encrypted, secretKey);
|
|
191
|
-
```
|
|
192
|
-
|
|
193
|
-
### 参数校验中间件
|
|
194
|
-
|
|
195
|
-
```javascript
|
|
196
|
-
import { validate, validateAll } from 'chanjs';
|
|
197
|
-
import { z } from 'zod';
|
|
198
|
-
|
|
199
|
-
// 单源校验
|
|
200
|
-
router.post('/user', validate('body', z.object({
|
|
201
|
-
name: z.string().min(1),
|
|
202
|
-
age: z.number().int().positive()
|
|
203
|
-
})), ctrl.create);
|
|
204
|
-
|
|
205
|
-
// 多源校验
|
|
206
|
-
router.post('/user', validateAll({
|
|
207
|
-
body: z.object({ name: z.string() }),
|
|
208
|
-
query: z.object({ page: z.coerce.number() })
|
|
209
|
-
}), ctrl.create);
|
|
210
|
-
```
|
|
211
|
-
|
|
212
|
-
### XSS 过滤
|
|
213
|
-
|
|
214
|
-
```javascript
|
|
215
|
-
import { filterXSS } from 'chanjs';
|
|
216
|
-
|
|
217
|
-
const safe = filterXSS('<script>alert("xss")</script>');
|
|
218
|
-
// 支持字符串、对象、数组递归过滤
|
|
219
|
-
```
|
|
220
|
-
|
|
221
|
-
### 关键词检测
|
|
222
|
-
|
|
223
|
-
```javascript
|
|
224
|
-
import { checkKeywords } from 'chanjs';
|
|
225
|
-
|
|
226
|
-
const result = checkKeywords('SELECT * FROM users');
|
|
227
|
-
// null 或 { category: 'sqlInjection', keyword: 'SELECT' }
|
|
228
|
-
```
|
|
229
|
-
|
|
230
|
-
### 限流中间件
|
|
231
|
-
|
|
232
|
-
```javascript
|
|
233
|
-
import { createRateLimitMiddleware } from 'chanjs';
|
|
234
|
-
|
|
235
|
-
const rateLimit = createRateLimitMiddleware({
|
|
236
|
-
windowMs: '1m', // 时间窗口,支持 '1s'/'1m'/'1h'/'1d' 格式
|
|
237
|
-
max: 100, // 窗口内最大请求数
|
|
238
|
-
ignorePaths: ['/api/public'] // 忽略路径
|
|
239
|
-
});
|
|
240
|
-
```
|
|
241
|
-
|
|
242
|
-
## 存储层
|
|
243
|
-
|
|
244
|
-
### cache - 内存缓存
|
|
245
|
-
|
|
246
|
-
```javascript
|
|
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); // 刷新过期时间
|
|
258
|
-
```
|
|
259
|
-
|
|
260
|
-
### store - 统一存储适配层
|
|
261
|
-
|
|
262
|
-
```javascript
|
|
263
|
-
import { store } from 'chanjs';
|
|
264
|
-
|
|
265
|
-
// 初始化(框架自动调用)
|
|
266
|
-
await store.init({ REDIS_ENABLED: false, REDIS: {} });
|
|
267
|
-
|
|
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);
|
|
276
|
-
|
|
277
|
-
// 诊断信息
|
|
278
|
-
store.getInfo();
|
|
279
|
-
// { mode: 'memory' | 'redis', memorySize, redisConnected, circuitOpen }
|
|
280
|
-
|
|
281
|
-
// 释放资源
|
|
282
|
-
await store.close();
|
|
283
|
-
```
|
|
284
|
-
|
|
285
|
-
## 工具模块
|
|
286
|
-
|
|
287
|
-
### helper 聚合对象
|
|
288
|
-
|
|
289
|
-
```javascript
|
|
290
|
-
import { helper } from 'chanjs';
|
|
291
|
-
|
|
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;
|
|
309
|
-
```
|
|
310
|
-
|
|
311
|
-
### loader 命名空间
|
|
312
|
-
|
|
313
|
-
```javascript
|
|
314
|
-
import { loader } from 'chanjs';
|
|
315
|
-
|
|
316
|
-
// 加载模块路由
|
|
317
|
-
await loader.loadModuleRouter(chan);
|
|
318
|
-
|
|
319
|
-
// 加载公共路由
|
|
320
|
-
await loader.loadCommonRouter(chan);
|
|
321
|
-
```
|
|
322
|
-
|
|
323
|
-
### utils 命名空间
|
|
324
|
-
|
|
325
|
-
```javascript
|
|
326
|
-
import { utils } from 'chanjs';
|
|
327
|
-
// 包含 helper 中的所有工具函数
|
|
328
|
-
```
|
|
329
|
-
|
|
330
|
-
## 日志
|
|
331
|
-
|
|
332
|
-
```javascript
|
|
333
|
-
import { logger, createLogger } from 'chanjs';
|
|
334
|
-
|
|
335
|
-
logger.info('信息日志');
|
|
336
|
-
logger.warn('警告日志');
|
|
337
|
-
logger.error('错误日志');
|
|
338
|
-
|
|
339
|
-
// 创建自定义 logger
|
|
340
|
-
const customLogger = createLogger('MyModule');
|
|
341
|
-
customLogger.info('自定义模块日志');
|
|
342
|
-
```
|
|
343
|
-
|
|
344
|
-
## 全局资源访问
|
|
345
|
-
|
|
346
|
-
Controller、Service、Repository 继承自 Container,可访问:
|
|
347
|
-
|
|
348
|
-
| 属性 | 说明 |
|
|
349
|
-
|------|------|
|
|
350
|
-
| `this.app` | 全局应用实例 |
|
|
351
|
-
| `this.config` | 全局配置对象 |
|
|
352
|
-
| `this.db` | 默认数据库连接 |
|
|
353
|
-
| `this.paths` | 路径工具对象 |
|
|
354
|
-
| `this.get(moduleName, fileName)` | 动态加载组件 |
|
|
355
|
-
|
|
356
|
-
## 错误码规范
|
|
357
|
-
|
|
358
|
-
| 范围 | 说明 |
|
|
359
|
-
|------|------|
|
|
360
|
-
| 0 | 成功 |
|
|
361
|
-
| 1xxx | 通用业务错误 |
|
|
362
|
-
| 5xxx | 系统错误 |
|
|
363
|
-
| 6xxx | 数据库错误 |
|
|
364
|
-
|
|
365
|
-
详见 [Common.md](./Common.md) 中的完整错误码列表。
|
|
366
|
-
|
|
367
|
-
## 目录结构
|
|
368
|
-
|
|
369
|
-
```
|
|
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) - 公共工具模块
|
package/doc/QuickStart.md
DELETED
|
@@ -1,116 +0,0 @@
|
|
|
1
|
-
# ChanJS 快速入门
|
|
2
|
-
|
|
3
|
-
## 安装
|
|
4
|
-
|
|
5
|
-
```bash
|
|
6
|
-
npm install chanjs
|
|
7
|
-
```
|
|
8
|
-
|
|
9
|
-
## 最小化启动
|
|
10
|
-
|
|
11
|
-
### 1. 创建入口文件 `index.js`
|
|
12
|
-
|
|
13
|
-
```javascript
|
|
14
|
-
import Chan from 'chanjs';
|
|
15
|
-
|
|
16
|
-
const app = new Chan();
|
|
17
|
-
await app.start();
|
|
18
|
-
app.run(port => {
|
|
19
|
-
console.log(`服务启动在端口 ${port}`);
|
|
20
|
-
});
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
### 2. 创建配置文件 `config/index.js`
|
|
24
|
-
|
|
25
|
-
```javascript
|
|
26
|
-
export default {
|
|
27
|
-
PORT: 3000,
|
|
28
|
-
NODE_ENV: 'dev',
|
|
29
|
-
|
|
30
|
-
// 数据库配置(可选)
|
|
31
|
-
db: [{
|
|
32
|
-
key: 'default',
|
|
33
|
-
client: 'mysql2',
|
|
34
|
-
connection: {
|
|
35
|
-
host: '127.0.0.1',
|
|
36
|
-
user: 'root',
|
|
37
|
-
password: '',
|
|
38
|
-
database: 'test'
|
|
39
|
-
}
|
|
40
|
-
}],
|
|
41
|
-
|
|
42
|
-
// 模块列表
|
|
43
|
-
modules: ['web', 'api']
|
|
44
|
-
};
|
|
45
|
-
```
|
|
46
|
-
|
|
47
|
-
### 3. 创建模块目录结构
|
|
48
|
-
|
|
49
|
-
```
|
|
50
|
-
app/
|
|
51
|
-
├── modules/
|
|
52
|
-
│ ├── web/
|
|
53
|
-
│ │ ├── controller/
|
|
54
|
-
│ │ │ └── IndexController.js
|
|
55
|
-
│ │ └── router.js
|
|
56
|
-
│ └── api/
|
|
57
|
-
│ ├── controller/
|
|
58
|
-
│ │ └── UserController.js
|
|
59
|
-
│ └── router.js
|
|
60
|
-
```
|
|
61
|
-
|
|
62
|
-
### 4. 创建控制器
|
|
63
|
-
|
|
64
|
-
```javascript
|
|
65
|
-
// app/modules/api/controller/UserController.js
|
|
66
|
-
import { Controller } from 'chanjs';
|
|
67
|
-
|
|
68
|
-
export default class UserController extends Controller {
|
|
69
|
-
async getUser(req, res) {
|
|
70
|
-
const { id } = req.params;
|
|
71
|
-
// 业务逻辑
|
|
72
|
-
return this.success({ data: { id, name: '张三' } });
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
```
|
|
76
|
-
|
|
77
|
-
### 5. 创建路由
|
|
78
|
-
|
|
79
|
-
```javascript
|
|
80
|
-
// app/modules/api/router.js
|
|
81
|
-
import { loader } from 'chanjs';
|
|
82
|
-
|
|
83
|
-
export default async function(app, router, config) {
|
|
84
|
-
const userCtrl = await loader.loadController('api', 'UserController');
|
|
85
|
-
|
|
86
|
-
router.get('/user/:id', userCtrl.getUser);
|
|
87
|
-
}
|
|
88
|
-
```
|
|
89
|
-
|
|
90
|
-
## 访问测试
|
|
91
|
-
|
|
92
|
-
```bash
|
|
93
|
-
curl http://localhost:3000/api/user/1
|
|
94
|
-
```
|
|
95
|
-
|
|
96
|
-
响应:
|
|
97
|
-
```json
|
|
98
|
-
{
|
|
99
|
-
"success": true,
|
|
100
|
-
"code": 0,
|
|
101
|
-
"msg": "操作成功",
|
|
102
|
-
"data": {
|
|
103
|
-
"id": "1",
|
|
104
|
-
"name": "张三"
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
```
|
|
108
|
-
|
|
109
|
-
## 下一步
|
|
110
|
-
|
|
111
|
-
- [Controller 控制器](./Controller.md) - 学习控制器编写规范
|
|
112
|
-
- [Service 服务层](./Service.md) - 业务逻辑层使用
|
|
113
|
-
- [Repository 数据层](./Repository.md) - 数据库操作
|
|
114
|
-
- [Cache 缓存](./Cache.md) - 缓存使用
|
|
115
|
-
- [Common 公共配置](./Common.md) - 全局配置说明
|
|
116
|
-
- [Help API 参考](./Help.md) - 完整 API 文档
|