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
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
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
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
site_host
|
|
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
|
|
164
|
-
|
|
165
|
-
|
|
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(
|
|
62
|
+
cache.set(ticketKey, result.ticket)
|
|
60
63
|
return result.ticket
|
|
61
64
|
}
|
|
62
65
|
|