q-koa 13.8.28 → 13.8.30

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/core/app.js CHANGED
@@ -143,22 +143,36 @@ class APP {
143
143
  // }));
144
144
  const { is_off = false } = this.config.restc
145
145
  if (!is_off) {
146
- this.app.use((ctx, next) => {
147
- const { url } = ctx.request
148
- const appName = url.split('/')[1]
149
- const excludes = [
150
- ...this.config.restc.excludes,
151
- ..._.get(ctx.app[appName], 'appConfig.restc.excludes', []).map(
152
- (item) => `/${appName}/${item}`
153
- ),
154
- ]
155
- this.app.use(
156
- restc.koa2({
157
- excludes,
158
- })
159
- )
160
- return next()
161
- })
146
+ /**
147
+ * restc中间件
148
+ * 注意:这里只构建不注册。实例按 appName 惰性创建并缓存(app 数量有限),
149
+ * 避免在中间件内部调用 app.use() 导致 middleware 数组每个请求增长一个实例。
150
+ * 实际注册在 initApp() 中路由注册之后,保持"兜底生效"的原有顺序。
151
+ */
152
+ const globalExcludes = [...this.config.restc.excludes]
153
+ // 兜底实例:无法识别 appName 时使用原始全局 excludes(不含 appName 前缀)
154
+ const fallbackRestc = restc.koa2({ excludes: globalExcludes })
155
+ const restcCache = new Map()
156
+ this.restcMiddleware = async (ctx, next) => {
157
+ const appName = ctx.request.url.split('/')[1]
158
+ const app = this.app[appName]
159
+ // 未注册应用统一走兜底实例,保证缓存有界(避免随机 appName 撑爆内存)
160
+ if (!app || !app.appConfig) {
161
+ return await fallbackRestc(ctx, next)
162
+ }
163
+ if (!restcCache.has(appName)) {
164
+ const excludes = [
165
+ // 全局 excludes 也必须拼 /${appName}/ 前缀,
166
+ // 否则 Gateway.test 做 indexOf(rule) === 0 前缀匹配时永远不命中
167
+ ...globalExcludes.map((item) => `/${appName}/${item}`),
168
+ ..._.get(app, 'appConfig.restc.excludes', []).map(
169
+ (item) => `/${appName}/${item}`
170
+ ),
171
+ ]
172
+ restcCache.set(appName, restc.koa2({ excludes }))
173
+ }
174
+ return await restcCache.get(appName)(ctx, next)
175
+ }
162
176
  }
163
177
 
164
178
  /**
@@ -217,6 +231,7 @@ class APP {
217
231
  * 挂在jwt解密方法
218
232
  */
219
233
  if (this.app[appName]) {
234
+ console.time('ss')
220
235
  this.app[appName].sign = async (user) => {
221
236
  const result = await jwt.sign(user, secret, {
222
237
  expiresIn,
@@ -224,6 +239,7 @@ class APP {
224
239
  })
225
240
  return result
226
241
  }
242
+ console.timeEnd('ss')
227
243
  }
228
244
  // eslint-disable-next-line no-nested-ternary
229
245
  ctx.request.clientType = ctx.header['client-type']
@@ -612,6 +628,11 @@ class APP {
612
628
  })
613
629
  this.app.use(router.routes()).use(router.allowedMethods())
614
630
 
631
+ // restc 排在路由之后注册:仅当没有其他中间件响应时才兜底生效(保持原有行为)
632
+ if (this.restcMiddleware) {
633
+ this.app.use(this.restcMiddleware)
634
+ }
635
+
615
636
  spinner.stop()
616
637
 
617
638
  console.log(chalk.green('==================== end ===================='))
@@ -6,6 +6,33 @@ const path = require('path')
6
6
  const fs = require('fs')
7
7
  const AlipaySdk = require('alipay-sdk').default
8
8
 
9
+ // 按 appId+appName+环境 缓存 AlipaySdk 实例,避免每请求重复读私钥文件 + 实例化
10
+ const alipaySdkCache = new Map()
11
+ function getAlipaySdk({ app_id, alipay_public_key, is_sandbox, appName, site_host }) {
12
+ const cacheKey = `${app_id}_${appName}_${is_sandbox ? 'sandbox' : 'prod'}_${site_host || ''}`
13
+ if (alipaySdkCache.has(cacheKey)) return alipaySdkCache.get(cacheKey)
14
+ const gateway = is_sandbox
15
+ ? 'https://openapi.alipaydev.com/gateway.do'
16
+ : 'https://openapi.alipay.com/gateway.do'
17
+ const notify_url = `https://${site_host || 'api.kuashou.com'}/${appName}/alipay/notify`
18
+ const sdk = new AlipaySdk({
19
+ appId: app_id,
20
+ signType: 'RSA2',
21
+ gateway,
22
+ alipayPublicKey: alipay_public_key,
23
+ privateKey: fs.readFileSync(
24
+ path.resolve(
25
+ __dirname,
26
+ `${process.cwd()}/app/${appName}/plugins/alipay/private-key.pem`
27
+ ),
28
+ 'ascii'
29
+ ),
30
+ notify_url,
31
+ })
32
+ alipaySdkCache.set(cacheKey, sdk)
33
+ return sdk
34
+ }
35
+
9
36
  exports.h5_pay = async (ctx) => {
10
37
  const { app, appName } = getAppByCtx(ctx)
11
38
 
@@ -95,27 +122,12 @@ exports.mp_pay = async (ctx) => {
95
122
  buyer_id = '2088722007804916',
96
123
  } = ctx.request.body
97
124
 
98
- const gateway = is_sandbox
99
- ? `https://openapi.alipaydev.com/gateway.do`
100
- : 'https://openapi.alipay.com/gateway.do'
101
-
102
- const notify_url = `https://${
103
- site_host || 'api.kuashou.com'
104
- }/${appName}/alipay/notify`
105
-
106
- const alipaySdk = new AlipaySdk({
107
- appId: app_id,
108
- signType: 'RSA2', // 签名算法,默认 RSA2
109
- gateway, // 支付宝网关地址 ,沙箱环境下使用时需要修改
110
- alipayPublicKey: alipay_public_key,
111
- privateKey: fs.readFileSync(
112
- path.resolve(
113
- __dirname,
114
- `${process.cwd()}/app/${appName}/plugins/alipay/private-key.pem`
115
- ),
116
- 'ascii'
117
- ),
118
- notify_url,
125
+ const alipaySdk = getAlipaySdk({
126
+ app_id,
127
+ alipay_public_key,
128
+ is_sandbox,
129
+ appName,
130
+ site_host,
119
131
  })
120
132
 
121
133
  const out_trade_no = _out_trade_no
@@ -160,11 +160,10 @@ exports.login = async (ctx) => {
160
160
  app,
161
161
  config,
162
162
  })
163
- const include = includeDefault.filter((i) => {
164
- return loginData.excludeInclude.every((m) => {
165
- return app.model[m] !== i.model
166
- })
167
- })
163
+ const excludeModels = new Set(
164
+ (loginData.excludeInclude || []).map((m) => app.model[m])
165
+ )
166
+ const include = includeDefault.filter((i) => !excludeModels.has(i.model))
168
167
 
169
168
  const attributes = {
170
169
  exclude: Array.from(
@@ -51,12 +51,15 @@ module.exports = class Singleton {
51
51
  }
52
52
 
53
53
  async getTicket() {
54
+ const { appid } = this.config
55
+ const ticketKey = `ticket_${appid}`
56
+ if (cache.has(ticketKey)) return cache.get(ticketKey)
54
57
  const access_token = await this.getAccessToken()
55
58
  const url = util.format(getTicketUrl, access_token)
56
59
  const result = await axios.get(url).then((res) => res.data)
57
60
  if (result.errcode) throw new Error(result.errmsg)
58
61
 
59
- cache.set('ticket', result.ticket)
62
+ cache.set(ticketKey, result.ticket)
60
63
  return result.ticket
61
64
  }
62
65
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "q-koa",
3
- "version": "13.8.28",
3
+ "version": "13.8.30",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "scripts": {