koa-ts-core 0.2.1 → 0.3.0
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 +149 -496
- package/dist/{init → core}/register_middleware.d.ts +2 -0
- package/dist/{init → core}/register_route.d.ts +2 -1
- package/dist/core/render_doc.d.ts +12 -0
- package/dist/core/swagger_collector.d.ts +22 -0
- package/dist/decorators/index.d.ts +3 -0
- package/dist/{decorate/router_decorate.d.ts → decorators/router.d.ts} +2 -10
- package/dist/decorators/swagger.d.ts +51 -0
- package/dist/decorators/validate.d.ts +9 -0
- package/dist/{base/exception.d.ts → exceptions/base.d.ts} +1 -0
- package/dist/exceptions/index.d.ts +1 -0
- package/dist/global.d.ts +5 -1
- package/dist/index.cjs.js +1 -39
- package/dist/index.d.ts +4 -3
- package/dist/index.esm.js +1 -39
- package/dist/{middleware/exception_middleware.d.ts → middlewares/exception.d.ts} +1 -1
- package/dist/types/core.d.ts +12 -0
- package/dist/utils/address.d.ts +2 -3
- package/dist/utils/functions.d.ts +1 -0
- package/dist/utils/path.d.ts +7 -4
- package/package.json +8 -6
- package/dist/base/index.d.ts +0 -1
- package/dist/decorate/index.d.ts +0 -1
- package/dist/init/render_doc.d.ts +0 -8
- /package/dist/{constant.d.ts → constants/index.d.ts} +0 -0
- /package/dist/{init/index.d.ts → core/app.d.ts} +0 -0
- /package/dist/{init → core}/register_controller.d.ts +0 -0
- /package/dist/{init → core}/register_env.d.ts +0 -0
- /package/dist/{init → core}/register_log.d.ts +0 -0
- /package/dist/{middleware/context_middleware.d.ts → middlewares/context.d.ts} +0 -0
- /package/dist/{middleware/logger_middleware.d.ts → middlewares/logger.d.ts} +0 -0
- /package/dist/{middleware/request_params_middleware.d.ts → middlewares/request_params.d.ts} +0 -0
- /package/dist/{middleware/router_middleware.d.ts → middlewares/router.d.ts} +0 -0
- /package/dist/{middleware/create_trackId_middleware.d.ts → middlewares/track_id.d.ts} +0 -0
package/README.md
CHANGED
|
@@ -1,125 +1,81 @@
|
|
|
1
1
|
# koa-ts-core
|
|
2
2
|
|
|
3
|
-
基于 **TypeScript + [Koa3](https://koajs.com/)**
|
|
3
|
+
基于 **TypeScript + [Koa3](https://koajs.com/)** 的轻量级企业级服务端核心框架。
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
- 权限与参数校验约定(控制器 + 校验器目录约定)
|
|
7
|
-
- 全局错误处理与统一响应体
|
|
8
|
-
- 环境变量加载(多环境合并)
|
|
9
|
-
- 日志集成(log4,基于 log4js)
|
|
10
|
-
- AsyncLocalStorage 请求上下文获取
|
|
11
|
-
- 阶段式中间件管线与扩展(Phase Middleware)
|
|
12
|
-
- TrackId(RequestId)生成与透传
|
|
13
|
-
- 接口文档生成基础能力(配合 `koa-ts-cli` 使用)
|
|
5
|
+
它提供了一套完整的开发约定与核心能力封装,包括装饰器路由、自动文档生成、链路追踪、全局异常处理等,旨在提升 Koa 项目的开发规范与效率。
|
|
14
6
|
|
|
15
|
-
> 推荐配合脚手架工具 [koa-ts-cli](https://www.npmjs.com/package/koa-typescript-cli)
|
|
7
|
+
> 推荐配合脚手架工具 [koa-ts-cli](https://www.npmjs.com/package/koa-typescript-cli) 使用最佳。
|
|
8
|
+
|
|
9
|
+
## 🌟 核心特性
|
|
10
|
+
|
|
11
|
+
- **装饰器路由**: 基于 `@koa/router` 封装,支持 `@Router`, `@AuthRouter`,风格类似 NestJS/Spring Boot。
|
|
12
|
+
- **Swagger/OpenAPI 自动生成**: 支持“零配置”扫描模式(配合 CLI)和“装饰器”定义模式。自动识别 Path/Query/Header/Body 参数。
|
|
13
|
+
- **全链路追踪 (Trace/Request ID)**: 基于 `AsyncLocalStorage`,内置 RequestId 生成与透传,支持全链路日志串联。
|
|
14
|
+
- **全局异常处理**: 统一捕获异常,规范化错误响应。
|
|
15
|
+
- **统一响应体**: 提供 `successRsp`, `errorRsp` 等工具函数,统一 API 返回格式。
|
|
16
|
+
- **阶段式中间件 (Phase Middleware)**: 独创的生命周期阶段管理,允许在 AsyncContext、Auth、Routing 等任意阶段前后注入中间件。
|
|
17
|
+
- **环境配置**: 自动加载 `.env.{environment}` 配置文件。
|
|
16
18
|
|
|
17
19
|
---
|
|
18
20
|
|
|
19
|
-
##
|
|
21
|
+
## 🚀 快速开始
|
|
22
|
+
|
|
23
|
+
### 安装
|
|
20
24
|
|
|
21
25
|
```bash
|
|
22
|
-
npm
|
|
26
|
+
npm install koa-ts-core reflect-metadata
|
|
23
27
|
# 或
|
|
24
|
-
|
|
25
|
-
# 或
|
|
26
|
-
pnpm add koa-ts-core
|
|
28
|
+
pnpm add koa-ts-core reflect-metadata
|
|
27
29
|
```
|
|
28
30
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
## 快速开始(推荐新 API)
|
|
31
|
+
> ⚠️ 注意:必须在入口文件顶部引入 `reflect-metadata`,且 `tsconfig.json` 需开启 `experimentalDecorators` 和 `emitDecoratorMetadata`。
|
|
32
32
|
|
|
33
|
-
###
|
|
33
|
+
### 初始化
|
|
34
34
|
|
|
35
|
-
|
|
35
|
+
在入口文件 (如 `src/main.ts`) 中初始化应用:
|
|
36
36
|
|
|
37
37
|
```ts
|
|
38
|
-
import
|
|
39
|
-
import cors from "koa2-cors";
|
|
38
|
+
import "reflect-metadata"; // 必须第一行引入
|
|
40
39
|
import { createKoaApp } from "koa-ts-core";
|
|
40
|
+
import Koa from "koa";
|
|
41
41
|
|
|
42
42
|
async function bootstrap() {
|
|
43
43
|
const [app] = await createKoaApp({
|
|
44
|
-
//
|
|
45
|
-
koaInstance: new Koa(),
|
|
46
|
-
|
|
47
|
-
//
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
44
|
+
// 基础配置
|
|
45
|
+
koaInstance: new Koa(), // 可选:传入自定义 Koa 实例
|
|
46
|
+
|
|
47
|
+
// Swagger 文档配置
|
|
48
|
+
swagger: {
|
|
49
|
+
enabled: true,
|
|
50
|
+
path: "/swagger-ui",
|
|
51
|
+
title: "My API Service",
|
|
52
|
+
version: "1.0.0"
|
|
53
53
|
},
|
|
54
54
|
|
|
55
|
-
//
|
|
55
|
+
// 错误处理
|
|
56
56
|
error: {
|
|
57
|
-
//
|
|
58
|
-
handler: (
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
}
|
|
62
|
-
// 是否在响应中暴露堆栈(默认:非生产环境为 true,生产为 false)
|
|
63
|
-
// exposeStack: process.env.NODE_ENV !== "production",
|
|
64
|
-
},
|
|
65
|
-
|
|
66
|
-
// 日志配置
|
|
67
|
-
log: {
|
|
68
|
-
// log4:基础日志能力(log4js)
|
|
69
|
-
// false 或不传:不启用 log4
|
|
70
|
-
// true: 使用默认 log4 配置
|
|
71
|
-
// 函数:自定义 log4 配置
|
|
72
|
-
log4: true,
|
|
73
|
-
|
|
74
|
-
// 是否开启每次请求的运行时日志
|
|
75
|
-
runtimeLog: true,
|
|
76
|
-
},
|
|
77
|
-
|
|
78
|
-
// Hook 配置:请求生命周期 request / response / error
|
|
79
|
-
hooks: {
|
|
80
|
-
register: (ctx, type) => {
|
|
81
|
-
// your tracing / metrics logic
|
|
82
|
-
// type: "request" | "response" | "error"
|
|
83
|
-
},
|
|
84
|
-
},
|
|
85
|
-
|
|
86
|
-
// CORS 中间件(例如 koa2-cors)
|
|
87
|
-
koa2Cors: cors(),
|
|
88
|
-
|
|
89
|
-
// TrackId(RequestId)配置
|
|
90
|
-
trackId: {
|
|
91
|
-
/**
|
|
92
|
-
* 生成 trackId 的函数:
|
|
93
|
-
* - 默认:优先从 header `x-request-id` 透传;没有就生成 uuid.v4()
|
|
94
|
-
* - 传入 false:禁用 trackId,不生成、不透传
|
|
95
|
-
*/
|
|
96
|
-
// generator: false,
|
|
97
|
-
|
|
98
|
-
// 是否写回响应头(默认 true)
|
|
99
|
-
exposeHeader: true,
|
|
100
|
-
|
|
101
|
-
// header 名称(默认 "x-request-id")
|
|
102
|
-
headerName: "x-request-id",
|
|
57
|
+
exposeStack: process.env.NODE_ENV === "development", // 开发环境暴露堆栈
|
|
58
|
+
handler: (err, ctx) => {
|
|
59
|
+
// 自定义错误上报逻辑 (如 Sentry)
|
|
60
|
+
console.error("Global Error Caught:", err);
|
|
61
|
+
}
|
|
103
62
|
},
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
// after: [yourCustomMiddleware],
|
|
115
|
-
// },
|
|
116
|
-
// },
|
|
63
|
+
|
|
64
|
+
// 全局鉴权回调 (配合 @AuthRouter)
|
|
65
|
+
auth: {
|
|
66
|
+
handler: async (ctx) => {
|
|
67
|
+
const token = ctx.header.authorization;
|
|
68
|
+
if (!token) throw new Error("Unauthorized");
|
|
69
|
+
// return true 表示通过
|
|
70
|
+
return true;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
117
73
|
});
|
|
118
74
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
);
|
|
75
|
+
const port = process.env.APP_PORT || 3000;
|
|
76
|
+
app.listen(port, () => {
|
|
77
|
+
console.log(`Server running at http://localhost:${port}`);
|
|
78
|
+
console.log(`Swagger UI: http://localhost:${port}/swagger-ui`);
|
|
123
79
|
});
|
|
124
80
|
}
|
|
125
81
|
|
|
@@ -128,470 +84,167 @@ bootstrap();
|
|
|
128
84
|
|
|
129
85
|
---
|
|
130
86
|
|
|
131
|
-
##
|
|
132
|
-
|
|
133
|
-
`createKoaApp(options?: Partial<CreateKoaOptions>)` 支持以下配置块:
|
|
134
|
-
|
|
135
|
-
### 基础
|
|
136
|
-
|
|
137
|
-
- **koaInstance?: Koa**
|
|
138
|
-
自定义 Koa 实例,不传则内部 `new Koa()`。
|
|
139
|
-
|
|
140
|
-
- **koa2Cors?: Koa.Middleware**
|
|
141
|
-
CORS 中间件,一般为 `koa2-cors()`。
|
|
142
|
-
|
|
143
|
-
- **phaseMiddlewares?: PhaseMiddlewareMap**
|
|
144
|
-
阶段式中间件扩展,按阶段插入自定义中间件,详见「中间件链路与阶段扩展」。
|
|
145
|
-
|
|
146
|
-
---
|
|
147
|
-
|
|
148
|
-
### 鉴权配置:`auth?: AuthConfig`
|
|
149
|
-
|
|
150
|
-
```ts
|
|
151
|
-
interface AuthConfig {
|
|
152
|
-
handler?: (ctx: Koa.Context) => Promise<boolean> | boolean;
|
|
153
|
-
}
|
|
154
|
-
```
|
|
155
|
-
|
|
156
|
-
- **handler**
|
|
157
|
-
鉴权回调,配合 `@AuthRouter` 使用。
|
|
158
|
-
你可以在这里检查登录态、角色、权限,抛错或返回布尔值。
|
|
159
|
-
|
|
160
|
-
---
|
|
161
|
-
|
|
162
|
-
### 错误处理配置:`error?: ErrorConfig`
|
|
163
|
-
|
|
164
|
-
```ts
|
|
165
|
-
interface ErrorConfig {
|
|
166
|
-
handler?: (error: unknown, ctx: Koa.Context) => void | Promise<void>;
|
|
167
|
-
exposeStack?: boolean; // 默认:非生产环境 true,生产 false
|
|
168
|
-
}
|
|
169
|
-
```
|
|
170
|
-
|
|
171
|
-
- **handler**
|
|
172
|
-
自定义错误回调,用于统一处理未捕获错误(日志、告警等)。
|
|
87
|
+
## 📚 API 参考
|
|
173
88
|
|
|
174
|
-
|
|
175
|
-
是否在响应中暴露错误堆栈信息,一般开发环境开启,生产关闭。
|
|
89
|
+
### 1. 路由装饰器 (Routing Decorators)
|
|
176
90
|
|
|
177
|
-
|
|
91
|
+
`koa-ts-core` 提供类级别和方法级别的路由定义。
|
|
178
92
|
|
|
179
|
-
|
|
93
|
+
#### `@Router(method, path)`
|
|
94
|
+
普通路由装饰器。
|
|
95
|
+
- `method`: 'get' | 'post' | 'put' | 'delete' | 'patch' | 'all' (默认 'get')
|
|
96
|
+
- `path`: 路由路径 (支持 path-to-regexp 语法,如 `/:id`)
|
|
180
97
|
|
|
181
98
|
```ts
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
99
|
+
import { Router, Context } from "koa-ts-core";
|
|
100
|
+
|
|
101
|
+
class UserController {
|
|
102
|
+
// GET /user/:id
|
|
103
|
+
@Router("get", "/user/:id")
|
|
104
|
+
async getUser(ctx: Context) {
|
|
105
|
+
const { id } = ctx.params;
|
|
106
|
+
ctx.body = { id };
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// 简写:不传参数默认 method='get', path='/方法名'
|
|
110
|
+
// GET /list
|
|
111
|
+
@Router()
|
|
112
|
+
async list(ctx: Context) { ... }
|
|
189
113
|
}
|
|
190
114
|
```
|
|
191
115
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
- `true`:使用默认 log4js 配置
|
|
196
|
-
- `(instance) => instance`: 自定义配置 log4js 实例
|
|
197
|
-
|
|
198
|
-
- **runtimeLog**
|
|
199
|
-
是否开启每次请求的运行时日志(挂载到 `ctx.runtimeLog`,配合内置 `loggerMiddleware` 使用)。
|
|
200
|
-
|
|
201
|
-
---
|
|
202
|
-
|
|
203
|
-
### Hook 配置:`hooks?: HookConfig`
|
|
116
|
+
#### `@AuthRouter(method, path)`
|
|
117
|
+
鉴权路由装饰器。
|
|
118
|
+
执行前会先调用 `createKoaApp` 中配置的 `auth.handler`,只有返回 `true` 才放行。
|
|
204
119
|
|
|
205
120
|
```ts
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
register?: (ctx: Koa.Context, type: HookType) => void;
|
|
121
|
+
@AuthRouter("post", "/admin/update")
|
|
122
|
+
async update(ctx: Context) {
|
|
123
|
+
// 只有鉴权通过才会执行这里
|
|
210
124
|
}
|
|
211
125
|
```
|
|
212
126
|
|
|
213
|
-
|
|
214
|
-
请求生命周期 hook,在请求开始/结束/异常时被调用,可用于埋点、监控。
|
|
127
|
+
### 2. Swagger / OpenAPI 装饰器
|
|
215
128
|
|
|
216
|
-
|
|
129
|
+
完全支持 OpenAPI 3.0 标准元数据定义。
|
|
217
130
|
|
|
218
|
-
|
|
131
|
+
- `@ApiTags(tags: string[])`: 定义 Controller 标签
|
|
132
|
+
- `@ApiOperation(summary, description)`: 接口摘要
|
|
133
|
+
- `@ApiParam(options)`: 定义 path 参数 (如 `/:id`)
|
|
134
|
+
- `@ApiQuery(options)`: 定义 query 参数
|
|
135
|
+
- `@ApiBody(options)`: 定义 request body
|
|
136
|
+
- `@ApiResponse(options)`: 定义响应结构
|
|
219
137
|
|
|
220
138
|
```ts
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
139
|
+
import { ApiTags, ApiOperation, ApiParam, ApiQuery, Router } from "koa-ts-core";
|
|
140
|
+
|
|
141
|
+
@ApiTags(["Order"])
|
|
142
|
+
class OrderController {
|
|
143
|
+
|
|
144
|
+
@Router("get", "/order/:orderId")
|
|
145
|
+
@ApiOperation("获取订单详情")
|
|
146
|
+
@ApiParam({ name: "orderId", description: "订单ID", example: "123" })
|
|
147
|
+
@ApiQuery({ name: "detail", required: false, description: "是否返回详情" })
|
|
148
|
+
async getOrder(ctx: Context) { ... }
|
|
231
149
|
}
|
|
232
150
|
```
|
|
233
151
|
|
|
234
|
-
-
|
|
235
|
-
|
|
236
|
-
- 不配置:默认使用 `x-request-id` header 或生成 `uuid.v4()`
|
|
237
|
-
- 设置为 `false`:禁用 trackId,不生成、不透传
|
|
238
|
-
- 自定义函数:可按业务需要生成(或透传) trackId
|
|
239
|
-
|
|
240
|
-
- **exposeHeader**
|
|
241
|
-
是否将 trackId 写回响应头(默认 `true`)。
|
|
242
|
-
|
|
243
|
-
- **headerName**
|
|
244
|
-
请求/响应中使用的 header 名称(默认 `"x-request-id"`)。
|
|
245
|
-
|
|
246
|
-
---
|
|
247
|
-
|
|
248
|
-
## 中间件链路与阶段扩展
|
|
249
|
-
|
|
250
|
-
框架将中间件链路拆分为多个“阶段”(`MiddlewarePhase`),内部按顺序执行,用户可在每个阶段前/后扩展中间件。
|
|
251
|
-
|
|
252
|
-
默认阶段顺序:
|
|
253
|
-
|
|
254
|
-
1. **AsyncContext**
|
|
255
|
-
AsyncLocalStorage 上下文中间件,保证在异步链路中可以获取当前请求的 `ctx`。
|
|
256
|
-
|
|
257
|
-
2. **TrackId**
|
|
258
|
-
TrackId 生成与透传中间件(根据 `trackId` 配置生成、挂载 `ctx.trackId`,并写入响应头)。
|
|
259
|
-
|
|
260
|
-
3. **ErrorHandling**
|
|
261
|
-
全局错误处理,中间件会捕获异常并调用 `error.handler`。
|
|
262
|
-
|
|
263
|
-
4. **Logging**
|
|
264
|
-
请求日志与耗时统计(结合 `log4` 和 `runtimeLog`)。
|
|
265
|
-
|
|
266
|
-
5. **Security**
|
|
267
|
-
CORS / 安全相关中间件(例如 `koa2-cors`)。
|
|
268
|
-
|
|
269
|
-
6. **BodyParsing**
|
|
270
|
-
`koa-bodyparser` + 请求参数挂载(`requestParamsMiddleware`)。
|
|
271
|
-
|
|
272
|
-
7. **Auth**
|
|
273
|
-
鉴权中间件,配合 `auth.handler` 与 `@AuthRouter`。
|
|
274
|
-
|
|
275
|
-
8. **Routing**
|
|
276
|
-
约定式路由分发(`@Router` / `@AuthRouter` + `@koa/router`)。
|
|
277
|
-
|
|
278
|
-
### 阶段扩展:PhaseMiddlewareMap
|
|
279
|
-
|
|
280
|
-
你可以在任意阶段插入自定义中间件:
|
|
281
|
-
|
|
282
|
-
```ts
|
|
283
|
-
import { MiddlewarePhase } from "koa-ts-core/types/core";
|
|
284
|
-
|
|
285
|
-
createKoaApp({
|
|
286
|
-
phaseMiddlewares: {
|
|
287
|
-
[MiddlewarePhase.Logging]: {
|
|
288
|
-
before: [
|
|
289
|
-
async (ctx, next) => {
|
|
290
|
-
// 在内置 Logging 中间件之前
|
|
291
|
-
await next();
|
|
292
|
-
},
|
|
293
|
-
],
|
|
294
|
-
use: [
|
|
295
|
-
async (ctx, next) => {
|
|
296
|
-
// 与内置 Logging 同阶段,追加在后面
|
|
297
|
-
await next();
|
|
298
|
-
},
|
|
299
|
-
],
|
|
300
|
-
after: [
|
|
301
|
-
async (ctx, next) => {
|
|
302
|
-
// 整个 Logging 阶段之后
|
|
303
|
-
await next();
|
|
304
|
-
},
|
|
305
|
-
],
|
|
306
|
-
},
|
|
307
|
-
},
|
|
308
|
-
});
|
|
309
|
-
```
|
|
310
|
-
|
|
311
|
-
每个阶段都支持 `before` / `use` / `after` 三种插入点。
|
|
312
|
-
|
|
313
|
-
---
|
|
314
|
-
|
|
315
|
-
## 获取当前请求上下文(AsyncLocalStorage)
|
|
316
|
-
|
|
317
|
-
框架通过 `AsyncLocalStorage` 在异步链路中保存 `Koa.Context`,无需层层传递 `ctx`,即可在任意业务代码中获取当前请求上下文。
|
|
318
|
-
|
|
319
|
-
`context_middleware` 已在 `AsyncContext` 阶段自动挂载,你只需要在业务侧使用工具函数:
|
|
320
|
-
|
|
321
|
-
```ts
|
|
322
|
-
// 示例:getCurrentContext.ts(具体导出以实际实现为准)
|
|
323
|
-
import { AsyncLocalStorage } from "async_hooks";
|
|
324
|
-
import type { Context } from "koa";
|
|
325
|
-
|
|
326
|
-
export const contextStore = new AsyncLocalStorage<Context>();
|
|
152
|
+
> **💡 自动扫描模式**:如果您使用 `koa-ts-cli doc` 生成了 `doc/` 目录,`swagger_collector` 会自动合并这些文档配置,无需手写繁琐的装饰器。
|
|
327
153
|
|
|
328
|
-
|
|
329
|
-
const context = contextStore.getStore();
|
|
330
|
-
if (!context) {
|
|
331
|
-
throw new Error("context is not exist");
|
|
332
|
-
}
|
|
333
|
-
return context;
|
|
334
|
-
};
|
|
335
|
-
```
|
|
154
|
+
### 3. 取用上下文 (Context Store)
|
|
336
155
|
|
|
337
|
-
|
|
156
|
+
无需在所有函数中透传 `ctx`。
|
|
338
157
|
|
|
339
158
|
```ts
|
|
340
159
|
import { getCurrentContext } from "koa-ts-core";
|
|
341
160
|
|
|
161
|
+
// 在任意 Service 或 Utils 中
|
|
342
162
|
function doSomething() {
|
|
343
163
|
const ctx = getCurrentContext();
|
|
344
|
-
|
|
345
|
-
ctx.
|
|
164
|
+
// 获取当前请求的 trackId
|
|
165
|
+
const traceId = ctx.trackId;
|
|
346
166
|
}
|
|
347
167
|
```
|
|
348
168
|
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
## 约定式路由
|
|
352
|
-
|
|
353
|
-
### 目录约定
|
|
169
|
+
### 4. 统一响应工具 (Response Helpers)
|
|
354
170
|
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
```text
|
|
358
|
-
src
|
|
359
|
-
└── controller
|
|
360
|
-
└── api
|
|
361
|
-
└── v1
|
|
362
|
-
└── user.ts
|
|
363
|
-
```
|
|
364
|
-
|
|
365
|
-
### 基础用法:@Router 与 @AuthRouter
|
|
171
|
+
提供了一组工具函数来标准化 API 返回结构 `{ code, message, data, trackId }`。
|
|
366
172
|
|
|
367
173
|
```ts
|
|
368
|
-
|
|
369
|
-
import { Context } from "koa";
|
|
370
|
-
import { Router, AuthRouter } from "koa-ts-core";
|
|
371
|
-
|
|
372
|
-
class User {
|
|
373
|
-
@Router("get", "/index/:userId")
|
|
374
|
-
async userInfo(ctx: Context) {
|
|
375
|
-
ctx.body = {
|
|
376
|
-
success: true,
|
|
377
|
-
userId: ctx.params.userId,
|
|
378
|
-
};
|
|
379
|
-
}
|
|
174
|
+
import { successRsp, errorRsp, unSuccessRsp } from "koa-ts-core";
|
|
380
175
|
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
ctx.body = {
|
|
385
|
-
success: true,
|
|
386
|
-
userName: ctx.params.user_name,
|
|
387
|
-
};
|
|
388
|
-
}
|
|
176
|
+
// 成功:HTTP 200, code=0
|
|
177
|
+
successRsp({ data: { id: 1 } });
|
|
178
|
+
// -> { code: 0, message: "success", data: { id: 1 }, trackId: "..." }
|
|
389
179
|
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
async setUserInfo(ctx: Context) {
|
|
393
|
-
ctx.body = {
|
|
394
|
-
success: true,
|
|
395
|
-
};
|
|
396
|
-
}
|
|
397
|
-
}
|
|
180
|
+
// 业务失败:HTTP 200, code!=0
|
|
181
|
+
unSuccessRsp({ code: 1001, message: "库存不足" });
|
|
398
182
|
|
|
399
|
-
|
|
183
|
+
// 异常:HTTP 400/500...
|
|
184
|
+
errorRsp(403, { message: "禁止访问" });
|
|
400
185
|
```
|
|
401
186
|
|
|
402
|
-
###
|
|
187
|
+
### 5. 异常处理 (BaseException)
|
|
403
188
|
|
|
404
|
-
|
|
189
|
+
推荐继承 `BaseException` 来抛出业务异常,通过全局错误中间件统一处理。
|
|
405
190
|
|
|
406
191
|
```ts
|
|
407
|
-
import
|
|
408
|
-
import { Router, successRsp } from "koa-ts-core";
|
|
409
|
-
|
|
410
|
-
class Test {
|
|
411
|
-
@Router()
|
|
412
|
-
async get_(ctx: Koa.Context) {
|
|
413
|
-
successRsp({ data: "get request" });
|
|
414
|
-
}
|
|
415
|
-
|
|
416
|
-
@Router()
|
|
417
|
-
async post(ctx: Koa.Context) {
|
|
418
|
-
successRsp({ data: "post request" });
|
|
419
|
-
}
|
|
420
|
-
|
|
421
|
-
@Router()
|
|
422
|
-
async put(ctx: Koa.Context) {
|
|
423
|
-
successRsp({ data: "put request" });
|
|
424
|
-
}
|
|
425
|
-
|
|
426
|
-
@Router()
|
|
427
|
-
async delete(ctx: Koa.Context) {
|
|
428
|
-
successRsp({ data: "delete request" });
|
|
429
|
-
}
|
|
430
|
-
|
|
431
|
-
@Router()
|
|
432
|
-
async patch(ctx: Koa.Context) {
|
|
433
|
-
successRsp({ data: "patch request" });
|
|
434
|
-
}
|
|
192
|
+
import { BaseException } from "koa-ts-core";
|
|
435
193
|
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
194
|
+
export class UserNotFoundException extends BaseException {
|
|
195
|
+
constructor() {
|
|
196
|
+
super("User not found");
|
|
197
|
+
this.code = 404001;
|
|
439
198
|
}
|
|
440
199
|
}
|
|
441
200
|
|
|
442
|
-
|
|
201
|
+
// 在业务中:
|
|
202
|
+
throw new UserNotFoundException();
|
|
203
|
+
// 响应: HTTP 500 (默认), body: { code: 404001, message: "User not found" ... }
|
|
443
204
|
```
|
|
444
205
|
|
|
445
|
-
> 实现基于 [`@koa/router`](https://www.npmjs.com/package/@koa/router),路由参数格式参考 [`path-to-regexp`](https://github.com/pillarjs/path-to-regexp)。
|
|
446
|
-
|
|
447
206
|
---
|
|
448
207
|
|
|
449
|
-
##
|
|
208
|
+
## 🛠 高级配置
|
|
450
209
|
|
|
451
|
-
###
|
|
210
|
+
### 阶段式中间件 (Phase Middleware)
|
|
452
211
|
|
|
453
|
-
|
|
212
|
+
`koa-ts-core` 将请求生命周期划分为多个阶段:
|
|
213
|
+
1. `AsyncContext` (上下文初始化)
|
|
214
|
+
2. `TrackId` (追踪ID生成)
|
|
215
|
+
3. `ErrorHandling` (全局错误捕获)
|
|
216
|
+
4. `Logging` (日志记录)
|
|
217
|
+
5. `Security` (Cors等)
|
|
218
|
+
6. `BodyParsing` (请求体解析)
|
|
219
|
+
7. `Auth` (鉴权)
|
|
220
|
+
8. `Routing` (路由执行)
|
|
454
221
|
|
|
455
|
-
|
|
456
|
-
src
|
|
457
|
-
├── controller
|
|
458
|
-
│ └── api/v1/user.ts # 控制器
|
|
459
|
-
└── validate
|
|
460
|
-
└── api/v1/user.ts # 参数校验器
|
|
461
|
-
```
|
|
462
|
-
|
|
463
|
-
示例:
|
|
222
|
+
您可以在 `createKoaApp` 时通过 `phaseMiddlewares` 选项,在任意阶段的前 (`before`)、后 (`after`) 或替换 (`use`) 该阶段。
|
|
464
223
|
|
|
465
224
|
```ts
|
|
466
|
-
|
|
467
|
-
import { Context } from "koa";
|
|
225
|
+
import { MiddlewarePhase } from "koa-ts-core";
|
|
468
226
|
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
227
|
+
createKoaApp({
|
|
228
|
+
phaseMiddlewares: {
|
|
229
|
+
[MiddlewarePhase.Auth]: {
|
|
230
|
+
before: [myCustomAuthCheckMiddleware] // 在内置 Auth 之前执行
|
|
473
231
|
}
|
|
474
232
|
}
|
|
475
|
-
}
|
|
476
|
-
|
|
477
|
-
export default UserValidate;
|
|
478
|
-
```
|
|
479
|
-
|
|
480
|
-
当路由命中 `userInfo` 时,会自动调用 `UserValidate.userInfo`,抛出的异常会进入统一错误处理。
|
|
481
|
-
|
|
482
|
-
---
|
|
483
|
-
|
|
484
|
-
## 统一响应工具
|
|
485
|
-
|
|
486
|
-
无需频繁访问 `ctx`,可使用以下工具构造统一格式响应:
|
|
487
|
-
|
|
488
|
-
```ts
|
|
489
|
-
/**
|
|
490
|
-
* 成功响应(HTTP 状态码 200)
|
|
491
|
-
*/
|
|
492
|
-
successRsp({ data, message });
|
|
493
|
-
|
|
494
|
-
/**
|
|
495
|
-
* 业务失败响应(HTTP 状态码仍为 200,但业务 code 非 0)
|
|
496
|
-
*/
|
|
497
|
-
unSuccessRsp({ code, message, data });
|
|
498
|
-
|
|
499
|
-
/**
|
|
500
|
-
* 异常响应(HTTP 状态码非 200)
|
|
501
|
-
*/
|
|
502
|
-
errorRsp(400, { message: "Bad Request" });
|
|
503
|
-
```
|
|
504
|
-
|
|
505
|
-
---
|
|
506
|
-
|
|
507
|
-
## 异常处理
|
|
508
|
-
|
|
509
|
-
提供基础异常类 `BaseException`,可扩展自定义业务异常:
|
|
510
|
-
|
|
511
|
-
```ts
|
|
512
|
-
import { BaseException } from "koa-ts-core";
|
|
513
|
-
|
|
514
|
-
export class CustomException extends BaseException {
|
|
515
|
-
code = 1000;
|
|
516
|
-
|
|
517
|
-
constructor(message: string) {
|
|
518
|
-
super(message);
|
|
519
|
-
}
|
|
520
|
-
}
|
|
521
|
-
|
|
522
|
-
// 使用
|
|
523
|
-
throw new CustomException("自定义异常");
|
|
524
|
-
```
|
|
525
|
-
|
|
526
|
-
所有异常会被内置错误处理中间件捕获,并结合 `error.handler` 输出日志或自定义处理。
|
|
527
|
-
|
|
528
|
-
---
|
|
529
|
-
|
|
530
|
-
## 环境变量加载
|
|
531
|
-
|
|
532
|
-
约定使用 [dotenv](https://www.npmjs.com/package/dotenv) 自动加载 `env` 目录:
|
|
533
|
-
|
|
534
|
-
```text
|
|
535
|
-
env
|
|
536
|
-
├── .common.env # 所有环境公用
|
|
537
|
-
├── .development.env # 开发环境
|
|
538
|
-
├── .production.env # 生产环境
|
|
539
|
-
└── .test.env # 测试环境
|
|
233
|
+
})
|
|
540
234
|
```
|
|
541
235
|
|
|
542
|
-
根据 `NODE_ENV` 加载对应文件,并合并 `.common.env`。
|
|
543
|
-
|
|
544
|
-
常用环境变量:
|
|
545
|
-
|
|
546
|
-
- `process.env.APP_PORT`:服务监听端口
|
|
547
|
-
- `process.env.ENV_DIR`:环境变量目录
|
|
548
|
-
- 其他自定义业务配置
|
|
549
|
-
|
|
550
236
|
---
|
|
551
237
|
|
|
552
|
-
##
|
|
553
|
-
|
|
554
|
-
`koa-ts-core` 提供路由元信息,配合 `koa-ts-cli` 的 `koa-ts-cli doc` 命令,可以根据 `src/controller` 自动生成接口配置,并在运行时通过 `/doc` 路由查看渲染后的接口文档(仅开发环境或 `DOC=true` 时启用)。
|
|
238
|
+
## 环境变量
|
|
555
239
|
|
|
556
|
-
|
|
240
|
+
约定根目录下 `env/` 文件夹:
|
|
241
|
+
- `.common.env` (公共配置)
|
|
242
|
+
- `.development.env` (开发环境)
|
|
243
|
+
- `.production.env` (生产环境)
|
|
557
244
|
|
|
558
245
|
---
|
|
559
246
|
|
|
560
|
-
##
|
|
561
|
-
|
|
562
|
-
框架对 `Koa.Context` 做了类型拓展,你可以在业务代码中使用这些字段:
|
|
563
|
-
|
|
564
|
-
```ts
|
|
565
|
-
declare module "koa" {
|
|
566
|
-
interface DefaultContext {
|
|
567
|
-
// log4js 实例
|
|
568
|
-
log4?: import("log4js").Log4js;
|
|
569
|
-
|
|
570
|
-
// 生命周期 hook
|
|
571
|
-
hook?: (ctx: Koa.Context, type: "request" | "response" | "error") => void;
|
|
572
|
-
|
|
573
|
-
// 是否启用运行时日志
|
|
574
|
-
runtimeLog: boolean;
|
|
575
|
-
|
|
576
|
-
// 校验后的参数
|
|
577
|
-
validated: {
|
|
578
|
-
params: Record<string, any>;
|
|
579
|
-
get: Record<string, any>;
|
|
580
|
-
post: Record<string, any>;
|
|
581
|
-
};
|
|
582
|
-
|
|
583
|
-
// trackId(请求 ID)
|
|
584
|
-
trackId?: string;
|
|
585
|
-
|
|
586
|
-
// 业务扩展字段
|
|
587
|
-
extra: {
|
|
588
|
-
get: Record<string, any>;
|
|
589
|
-
post: Record<string, any>;
|
|
590
|
-
};
|
|
591
|
-
}
|
|
592
|
-
}
|
|
593
|
-
```
|
|
594
|
-
|
|
595
|
-
## 相关项目
|
|
247
|
+
## 🔗 相关链接
|
|
596
248
|
|
|
597
|
-
- [
|
|
249
|
+
- [GitHub仓库](https://github.com/SuPeiSen/koa-ts-core)
|
|
250
|
+
- [koa-ts-cli 脚手架](https://github.com/SuPeiSen/koa-ts-cli)
|