From eede990ec8639a244664232bb4c415277ec5ed49 Mon Sep 17 00:00:00 2001 From: xion Date: Thu, 15 May 2025 22:32:05 +0800 Subject: [PATCH] =?UTF-8?q?perf:=20=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 9 ++++---- src/router-define.ts | 50 +++++++++++++++++++++++++++++++++------- src/router-simple.ts | 3 ++- src/server/parse-body.ts | 34 ++++++++++++++++++++++++++- 4 files changed, 82 insertions(+), 14 deletions(-) diff --git a/package.json b/package.json index c1ce11e..046bc8b 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package", "name": "@kevisual/router", - "version": "0.0.18", + "version": "0.0.20", "description": "", "type": "module", "main": "./dist/router.js", @@ -21,18 +21,19 @@ "author": "abearxiong", "license": "MIT", "devDependencies": { + "@kevisual/query": "^0.0.18", "@rollup/plugin-alias": "^5.1.1", "@rollup/plugin-commonjs": "^28.0.3", "@rollup/plugin-node-resolve": "^16.0.1", "@rollup/plugin-typescript": "^12.1.2", "@types/lodash-es": "^4.17.12", - "@types/node": "^22.14.1", + "@types/node": "^22.15.18", "@types/ws": "^8.18.1", "@types/xml2js": "^0.4.14", "cookie": "^1.0.2", "lodash-es": "^4.17.21", "nanoid": "^5.1.5", - "rollup": "^4.40.0", + "rollup": "^4.40.2", "rollup-plugin-dts": "^6.2.1", "ts-loader": "^9.5.2", "ts-node": "^10.9.2", @@ -40,7 +41,7 @@ "typescript": "^5.8.3", "ws": "npm:@kevisual/ws", "xml2js": "^0.6.2", - "zod": "^3.24.3" + "zod": "^3.24.4" }, "repository": { "type": "git", diff --git a/src/router-define.ts b/src/router-define.ts index af8f294..49dfcdf 100644 --- a/src/router-define.ts +++ b/src/router-define.ts @@ -1,5 +1,5 @@ import type { QueryRouterServer, RouteOpts, Run, RouteMiddleware } from '@kevisual/router'; - +import type { DataOpts, Query, Result } from '@kevisual/query/query'; // export type RouteObject = { // [K in T[number]]: RouteOpts; // }; @@ -70,17 +70,46 @@ class Chain { return this; } } +type QueryChainOptions = { + query?: Query; + omitKeys?: string[]; +}; class QueryChain { obj: SimpleObject = {}; - constructor(value?: SimpleObject, opts?: SimpleObject) { + query: Query; + omitKeys: string[] = ['metadata', 'description', 'validator']; + constructor(value?: SimpleObject, opts?: QueryChainOptions) { this.obj = value || {}; + this.query = opts?.query; + if (opts?.omitKeys) this.omitKeys = opts.omitKeys; } - get(queryData?: Record): Pick { + omit(obj: SimpleObject, key: string[] = []) { + const newObj = { ...obj }; + key.forEach((k) => { + delete newObj[k]; + }); + return newObj; + } + /** + * 生成 + * @param queryData + * @returns + */ + getKey(queryData?: SimpleObject): Pick { + const obj = this.omit(this.obj, this.omitKeys); return { - ...this.obj, + ...obj, ...queryData, }; } + post(data: P, options?: DataOpts): Promise> { + const _queryData = this.getKey(data); + return this.query.post(_queryData, options); + } + get(data: P, options?: DataOpts): Promise> { + const _queryData = this.getKey(data); + return this.query.get(_queryData, options); + } } export const util = { getChain: (obj: RouteOpts, opts?: ChainOptions) => { @@ -91,9 +120,11 @@ export const util = { export class QueryUtil { obj: T; app: QueryRouterServer; - constructor(object: T, opts?: ChainOptions) { + query: Query; + constructor(object: T, opts?: ChainOptions & QueryChainOptions) { this.obj = object; this.app = opts?.app; + this.query = opts?.query; } static createFormObj(object: U, opts?: ChainOptions) { return new QueryUtil(object, opts); @@ -108,12 +139,15 @@ export class QueryUtil { chain(key: K, opts?: ChainOptions) { const obj = this.obj[key]; let newOpts = { app: this.app, ...opts }; - return new Chain(obj, newOpts); + return new QueryUtil.Chain(obj, newOpts); } - queryChain(key: K) { + queryChain(key: K, opts?: QueryChainOptions) { const value = this.obj[key]; - return new QueryChain(value); + let newOpts = { query: this.query, ...opts }; + return new QueryUtil.QueryChain(value, newOpts); } + static Chain = Chain; + static QueryChain = QueryChain; get routeObject() { return this.obj; } diff --git a/src/router-simple.ts b/src/router-simple.ts index 101bad6..8eeeef0 100644 --- a/src/router-simple.ts +++ b/src/router-simple.ts @@ -1,6 +1,6 @@ import { pathToRegexp, Key } from 'path-to-regexp'; import type { IncomingMessage, ServerResponse } from 'node:http'; -import { parseBody, parseSearch } from './server/parse-body.ts'; +import { parseBody, parseSearch, parseSearchValue } from './server/parse-body.ts'; type Req = IncomingMessage & { params?: Record }; interface Route { @@ -24,6 +24,7 @@ export class SimpleRouter { getSearch(req: Req) { return parseSearch(req); } + parseSearchValue = parseSearchValue; use(method: string, route: string, ...fns: Array<(req: Req, res: ServerResponse) => Promise | void>) { const handlers = Array.isArray(fns) ? fns.flat() : []; const pattern = pathToRegexp(route); diff --git a/src/server/parse-body.ts b/src/server/parse-body.ts index ffa990c..3beb9f7 100644 --- a/src/server/parse-body.ts +++ b/src/server/parse-body.ts @@ -10,7 +10,39 @@ export const parseBody = async >(req: IncomingMessage) = req.on('end', () => { try { const body = Buffer.concat(arr).toString(); - resolve(JSON.parse(body)); + + // 获取 Content-Type 头信息 + const contentType = req.headers['content-type'] || ''; + + // 处理 application/json + if (contentType.includes('application/json')) { + resolve(JSON.parse(body) as T); + return; + } + // 处理 application/x-www-form-urlencoded + if (contentType.includes('application/x-www-form-urlencoded')) { + const formData = new URLSearchParams(body); + const result: Record = {}; + + formData.forEach((value, key) => { + // 尝试将值解析为 JSON,如果失败则保留原始字符串 + try { + result[key] = JSON.parse(value); + } catch { + result[key] = value; + } + }); + + resolve(result as T); + return; + } + + // 默认尝试 JSON 解析 + try { + resolve(JSON.parse(body) as T); + } catch { + resolve({} as T); + } } catch (e) { resolve({} as T); }