befly 3.9.11 → 3.9.12
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/hooks/parser.ts +31 -10
- package/package.json +2 -2
- package/router/api.ts +11 -2
- package/types/api.d.ts +12 -0
package/hooks/parser.ts
CHANGED
|
@@ -25,31 +25,52 @@ const hook: Hook = {
|
|
|
25
25
|
// GET 请求:解析查询参数
|
|
26
26
|
if (ctx.req.method === 'GET') {
|
|
27
27
|
const url = new URL(ctx.req.url);
|
|
28
|
-
|
|
29
|
-
|
|
28
|
+
const params = Object.fromEntries(url.searchParams);
|
|
29
|
+
// rawBody 模式:保留完整请求参数,不过滤字段
|
|
30
|
+
if (ctx.api.rawBody) {
|
|
31
|
+
ctx.body = params;
|
|
32
|
+
} else if (isPlainObject(ctx.api.fields) && !isEmpty(ctx.api.fields)) {
|
|
33
|
+
ctx.body = pickFields(params, Object.keys(ctx.api.fields));
|
|
30
34
|
} else {
|
|
31
|
-
ctx.body =
|
|
35
|
+
ctx.body = params;
|
|
32
36
|
}
|
|
33
37
|
} else if (ctx.req.method === 'POST') {
|
|
34
38
|
// POST 请求:解析请求体
|
|
35
39
|
const contentType = ctx.req.headers.get('content-type') || '';
|
|
40
|
+
// 获取 URL 查询参数(POST 请求也可能带参数,如微信回调)
|
|
41
|
+
const url = new URL(ctx.req.url);
|
|
42
|
+
const queryParams = Object.fromEntries(url.searchParams);
|
|
43
|
+
|
|
36
44
|
try {
|
|
37
45
|
// JSON 格式
|
|
38
46
|
if (contentType.includes('application/json')) {
|
|
39
47
|
const body = (await ctx.req.json()) as Record<string, any>;
|
|
40
|
-
|
|
41
|
-
|
|
48
|
+
// 合并 URL 参数和请求体(请求体优先)
|
|
49
|
+
const merged = { ...queryParams, ...body };
|
|
50
|
+
// rawBody 模式:保留完整请求体,不过滤字段
|
|
51
|
+
if (ctx.api.rawBody) {
|
|
52
|
+
ctx.body = merged;
|
|
53
|
+
} else if (isPlainObject(ctx.api.fields) && !isEmpty(ctx.api.fields)) {
|
|
54
|
+
ctx.body = pickFields(merged, Object.keys(ctx.api.fields));
|
|
42
55
|
} else {
|
|
43
|
-
ctx.body =
|
|
56
|
+
ctx.body = merged;
|
|
44
57
|
}
|
|
45
58
|
} else if (contentType.includes('application/xml') || contentType.includes('text/xml')) {
|
|
46
59
|
// XML 格式
|
|
47
60
|
const text = await ctx.req.text();
|
|
48
|
-
const
|
|
49
|
-
|
|
50
|
-
|
|
61
|
+
const parsed = xmlParser.parse(text) as Record<string, any>;
|
|
62
|
+
// 提取根节点内容(如 xml),使 body 扁平化
|
|
63
|
+
const rootKey = Object.keys(parsed)[0];
|
|
64
|
+
const body = rootKey && typeof parsed[rootKey] === 'object' ? parsed[rootKey] : parsed;
|
|
65
|
+
// 合并 URL 参数和请求体(请求体优先)
|
|
66
|
+
const merged = { ...queryParams, ...body };
|
|
67
|
+
// rawBody 模式:保留完整请求体,不过滤字段
|
|
68
|
+
if (ctx.api.rawBody) {
|
|
69
|
+
ctx.body = merged;
|
|
70
|
+
} else if (isPlainObject(ctx.api.fields) && !isEmpty(ctx.api.fields)) {
|
|
71
|
+
ctx.body = pickFields(merged, Object.keys(ctx.api.fields));
|
|
51
72
|
} else {
|
|
52
|
-
ctx.body =
|
|
73
|
+
ctx.body = merged;
|
|
53
74
|
}
|
|
54
75
|
} else {
|
|
55
76
|
// 不支持的 Content-Type
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "befly",
|
|
3
|
-
"version": "3.9.
|
|
3
|
+
"version": "3.9.12",
|
|
4
4
|
"description": "Befly - 为 Bun 专属打造的 TypeScript API 接口框架核心引擎",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"private": false,
|
|
@@ -74,7 +74,7 @@
|
|
|
74
74
|
"pino": "^10.1.0",
|
|
75
75
|
"pino-roll": "^4.0.0"
|
|
76
76
|
},
|
|
77
|
-
"gitHead": "
|
|
77
|
+
"gitHead": "1065d8c11e32a4d9cf6177ad484500c4c98b1e2f",
|
|
78
78
|
"devDependencies": {
|
|
79
79
|
"typescript": "^5.9.3"
|
|
80
80
|
}
|
package/router/api.ts
CHANGED
|
@@ -61,7 +61,16 @@ export function apiHandler(apis: Map<string, ApiRoute>, hooks: Hook[], context:
|
|
|
61
61
|
}
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
-
// 5. 执行
|
|
64
|
+
// 5. 执行 preprocess 预处理(如果有)
|
|
65
|
+
if (ctx.api?.preprocess) {
|
|
66
|
+
await ctx.api.preprocess(context, ctx);
|
|
67
|
+
// 如果 preprocess 设置了 response,停止执行
|
|
68
|
+
if (ctx.response) {
|
|
69
|
+
return ctx.response;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// 6. 执行 API handler
|
|
65
74
|
if (!ctx.api) {
|
|
66
75
|
if (req.method !== 'OPTIONS') {
|
|
67
76
|
ctx.response = Response.json(
|
|
@@ -84,7 +93,7 @@ export function apiHandler(apis: Map<string, ApiRoute>, hooks: Hook[], context:
|
|
|
84
93
|
}
|
|
85
94
|
}
|
|
86
95
|
|
|
87
|
-
//
|
|
96
|
+
// 7. 返回响应(自动处理 response/result/日志)
|
|
88
97
|
return FinalResponse(ctx);
|
|
89
98
|
} catch (err: any) {
|
|
90
99
|
// 全局错误处理
|
package/types/api.d.ts
CHANGED
|
@@ -85,6 +85,18 @@ export interface ApiRoute<T = any, R = any> {
|
|
|
85
85
|
/** 必填字段(可选,默认 []) */
|
|
86
86
|
required?: string[];
|
|
87
87
|
|
|
88
|
+
/** 是否保留原始请求体(可选,默认 false)
|
|
89
|
+
* - true: 不过滤字段,保留完整请求体(适用于微信回调、webhook 等场景)
|
|
90
|
+
* - false: 根据 fields 定义过滤字段
|
|
91
|
+
*/
|
|
92
|
+
rawBody?: boolean;
|
|
93
|
+
|
|
94
|
+
/** 请求预处理函数(可选,在 handler 之前执行)
|
|
95
|
+
* 用于解密、转换请求数据等场景
|
|
96
|
+
* 可以修改 ctx.body
|
|
97
|
+
*/
|
|
98
|
+
preprocess?: ApiHandler<T, void>;
|
|
99
|
+
|
|
88
100
|
/** 缓存配置(可选,单位:秒) */
|
|
89
101
|
cache?: number;
|
|
90
102
|
|