@faasjs/http 0.0.2-beta.3 → 0.0.2-beta.302
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 +1 -1
- package/lib/cookie.d.ts +9 -13
- package/lib/index.d.ts +43 -35
- package/lib/index.es.js +194 -173
- package/lib/index.js +197 -176
- package/lib/session.d.ts +16 -15
- package/lib/validator.d.ts +38 -23
- package/package.json +16 -3
package/lib/index.es.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
1
|
+
import { usePlugin } from '@faasjs/func';
|
|
2
|
+
import { deepMerge } from '@faasjs/deep_merge';
|
|
3
|
+
import { Logger } from '@faasjs/logger';
|
|
3
4
|
import { randomBytes, pbkdf2Sync, createCipheriv, createHmac, createDecipheriv } from 'crypto';
|
|
5
|
+
import { brotliCompressSync, gzipSync, deflateSync } from 'zlib';
|
|
4
6
|
|
|
5
7
|
class Session {
|
|
6
8
|
constructor(cookie, config) {
|
|
@@ -30,9 +32,8 @@ class Session {
|
|
|
30
32
|
this.changed = false;
|
|
31
33
|
}
|
|
32
34
|
encode(text) {
|
|
33
|
-
if (typeof text !== 'string')
|
|
35
|
+
if (typeof text !== 'string')
|
|
34
36
|
text = JSON.stringify(text);
|
|
35
|
-
}
|
|
36
37
|
const iv = randomBytes(16);
|
|
37
38
|
const cipher = createCipheriv(this.config.cipherName, this.secret, iv);
|
|
38
39
|
const encrypted = Buffer.concat([cipher.update(text), cipher.final()]).toString('base64');
|
|
@@ -48,9 +49,8 @@ class Session {
|
|
|
48
49
|
const hmac = createHmac(this.config.digest, this.signedSecret);
|
|
49
50
|
hmac.update(signedParts[0]);
|
|
50
51
|
const digest = hmac.digest('hex');
|
|
51
|
-
if (signedParts[1] !== digest)
|
|
52
|
+
if (signedParts[1] !== digest)
|
|
52
53
|
throw Error('Not valid');
|
|
53
|
-
}
|
|
54
54
|
const message = Buffer.from(signedParts[0], 'base64').toString();
|
|
55
55
|
const parts = message.split('--').map(function (part) {
|
|
56
56
|
return Buffer.from(part, 'base64');
|
|
@@ -58,26 +58,23 @@ class Session {
|
|
|
58
58
|
const cipher = createDecipheriv(this.config.cipherName, this.secret, parts[1]);
|
|
59
59
|
const part = Buffer.from(cipher.update(parts[0])).toString('utf8');
|
|
60
60
|
const final = cipher.final('utf8');
|
|
61
|
-
const
|
|
62
|
-
return JSON.parse(
|
|
61
|
+
const decrypt = [part, final].join('');
|
|
62
|
+
return JSON.parse(decrypt);
|
|
63
63
|
}
|
|
64
64
|
read(key) {
|
|
65
65
|
return this.content[key];
|
|
66
66
|
}
|
|
67
67
|
write(key, value) {
|
|
68
|
-
if (value === null || typeof value === 'undefined')
|
|
68
|
+
if (value === null || typeof value === 'undefined')
|
|
69
69
|
delete this.content[key];
|
|
70
|
-
|
|
71
|
-
else {
|
|
70
|
+
else
|
|
72
71
|
this.content[key] = value;
|
|
73
|
-
}
|
|
74
72
|
this.changed = true;
|
|
75
73
|
return this;
|
|
76
74
|
}
|
|
77
75
|
update() {
|
|
78
|
-
if (this.changed)
|
|
76
|
+
if (this.changed)
|
|
79
77
|
this.cookie.write(this.config.key, this.encode(JSON.stringify(this.content)));
|
|
80
|
-
}
|
|
81
78
|
return this;
|
|
82
79
|
}
|
|
83
80
|
}
|
|
@@ -98,15 +95,13 @@ class Cookie {
|
|
|
98
95
|
invoke(cookie) {
|
|
99
96
|
this.content = Object.create(null);
|
|
100
97
|
// 解析 cookie
|
|
101
|
-
if (cookie)
|
|
102
|
-
cookie.split(';').
|
|
98
|
+
if (cookie)
|
|
99
|
+
cookie.split(';').forEach(x => {
|
|
103
100
|
x = x.trim();
|
|
104
|
-
const k =
|
|
105
|
-
if (k !== null)
|
|
101
|
+
const k = /([^=]+)/.exec(x);
|
|
102
|
+
if (k !== null)
|
|
106
103
|
this.content[k[0]] = decodeURIComponent(x.replace(`${k[0]}=`, '').replace(/;$/, ''));
|
|
107
|
-
}
|
|
108
104
|
});
|
|
109
|
-
}
|
|
110
105
|
this.setCookie = Object.create(null);
|
|
111
106
|
// 预读取 session
|
|
112
107
|
this.session.invoke(this.read(this.session.config.key));
|
|
@@ -127,78 +122,60 @@ class Cookie {
|
|
|
127
122
|
cookie = `${key}=${encodeURIComponent(value)};`;
|
|
128
123
|
this.content[key] = value;
|
|
129
124
|
}
|
|
130
|
-
if (typeof opts.expires === 'number')
|
|
125
|
+
if (typeof opts.expires === 'number')
|
|
131
126
|
cookie += `max-age=${opts.expires};`;
|
|
132
|
-
|
|
133
|
-
else if (typeof opts.expires === 'string') {
|
|
127
|
+
else if (typeof opts.expires === 'string')
|
|
134
128
|
cookie += `expires=${opts.expires};`;
|
|
135
|
-
}
|
|
136
129
|
cookie += `path=${opts.path || '/'};`;
|
|
137
|
-
if (opts.domain)
|
|
130
|
+
if (opts.domain)
|
|
138
131
|
cookie += `domain=${opts.domain};`;
|
|
139
|
-
|
|
140
|
-
if (opts.secure) {
|
|
132
|
+
if (opts.secure)
|
|
141
133
|
cookie += 'Secure;';
|
|
142
|
-
|
|
143
|
-
if (opts.httpOnly) {
|
|
134
|
+
if (opts.httpOnly)
|
|
144
135
|
cookie += 'HttpOnly;';
|
|
145
|
-
|
|
146
|
-
if (opts.sameSite) {
|
|
136
|
+
if (opts.sameSite)
|
|
147
137
|
cookie += `SameSite=${opts.sameSite};`;
|
|
148
|
-
}
|
|
149
138
|
this.setCookie[key] = cookie;
|
|
150
139
|
return this;
|
|
151
140
|
}
|
|
152
141
|
headers() {
|
|
153
|
-
if (
|
|
142
|
+
if (Object.keys(this.setCookie).length === 0)
|
|
154
143
|
return {};
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
return {
|
|
158
|
-
'Set-Cookie': Object.values(this.setCookie)
|
|
159
|
-
};
|
|
160
|
-
}
|
|
144
|
+
else
|
|
145
|
+
return { 'Set-Cookie': Object.values(this.setCookie) };
|
|
161
146
|
}
|
|
162
147
|
}
|
|
163
148
|
|
|
164
|
-
class ValidError extends Error {
|
|
165
|
-
constructor({ statusCode, headers, message }) {
|
|
166
|
-
super(message);
|
|
167
|
-
this.statusCode = statusCode || 500;
|
|
168
|
-
this.headers = headers || Object.create(null);
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
149
|
class Validator {
|
|
172
|
-
constructor(config) {
|
|
150
|
+
constructor(config, logger) {
|
|
173
151
|
this.paramsConfig = config.params;
|
|
174
152
|
this.cookieConfig = config.cookie;
|
|
175
153
|
this.sessionConfig = config.session;
|
|
176
|
-
this.
|
|
154
|
+
this.before = config.before;
|
|
155
|
+
this.logger = logger;
|
|
177
156
|
}
|
|
178
|
-
valid(
|
|
179
|
-
this.
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
}
|
|
184
|
-
this.
|
|
185
|
-
if (this.paramsConfig) {
|
|
186
|
-
this.logger.debug('Valid
|
|
187
|
-
this.validContent('params', params, '', this.paramsConfig);
|
|
188
|
-
}
|
|
189
|
-
if (this.cookieConfig) {
|
|
190
|
-
this.logger.debug('Valid
|
|
191
|
-
if (
|
|
157
|
+
async valid(request) {
|
|
158
|
+
if (this.before) {
|
|
159
|
+
const result = await this.before(request);
|
|
160
|
+
if (result)
|
|
161
|
+
throw new HttpError(result);
|
|
162
|
+
}
|
|
163
|
+
this.request = request;
|
|
164
|
+
if (this.paramsConfig && request.params) {
|
|
165
|
+
this.logger.debug('Valid Params');
|
|
166
|
+
this.validContent('params', request.params, '', this.paramsConfig);
|
|
167
|
+
}
|
|
168
|
+
if (this.cookieConfig && request.cookie) {
|
|
169
|
+
this.logger.debug('Valid Cookie');
|
|
170
|
+
if (request.cookie == null)
|
|
192
171
|
throw Error('Not found Cookie');
|
|
193
|
-
|
|
194
|
-
this.validContent('cookie', cookie.content, '', this.cookieConfig);
|
|
172
|
+
this.validContent('cookie', request.cookie.content, '', this.cookieConfig);
|
|
195
173
|
}
|
|
196
|
-
if (this.sessionConfig) {
|
|
174
|
+
if (this.sessionConfig && request.session) {
|
|
197
175
|
this.logger.debug('Valid Session');
|
|
198
|
-
if (
|
|
176
|
+
if (request.session == null)
|
|
199
177
|
throw Error('Not found Session');
|
|
200
|
-
|
|
201
|
-
this.validContent('session', session.content, '', this.sessionConfig);
|
|
178
|
+
this.validContent('session', request.session.content, '', this.sessionConfig);
|
|
202
179
|
}
|
|
203
180
|
}
|
|
204
181
|
validContent(type, params, baseKey, config) {
|
|
@@ -206,57 +183,50 @@ class Validator {
|
|
|
206
183
|
const paramsKeys = Object.keys(params);
|
|
207
184
|
const rulesKeys = Object.keys(config.rules);
|
|
208
185
|
const diff = paramsKeys.filter(k => !rulesKeys.includes(k));
|
|
209
|
-
if (diff.length)
|
|
186
|
+
if (diff.length > 0)
|
|
210
187
|
if (config.whitelist === 'error') {
|
|
211
188
|
const diffKeys = diff.map(k => `${baseKey}${k}`);
|
|
212
|
-
const error = Error(`[${type}]
|
|
189
|
+
const error = Error(`[${type}] Not permitted keys: ${diffKeys.join(', ')}`);
|
|
213
190
|
if (config.onError) {
|
|
214
191
|
const res = config.onError(`${type}.whitelist`, baseKey, diffKeys);
|
|
215
|
-
if (res)
|
|
216
|
-
throw new
|
|
217
|
-
}
|
|
192
|
+
if (res)
|
|
193
|
+
throw new HttpError(res);
|
|
218
194
|
}
|
|
219
195
|
throw error;
|
|
220
196
|
}
|
|
221
|
-
else if (config.whitelist === 'ignore')
|
|
222
|
-
for (const key of diff)
|
|
197
|
+
else if (config.whitelist === 'ignore')
|
|
198
|
+
for (const key of diff)
|
|
223
199
|
delete params[key];
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
200
|
}
|
|
228
201
|
for (const key in config.rules) {
|
|
229
202
|
const rule = config.rules[key];
|
|
203
|
+
if (!rule)
|
|
204
|
+
continue;
|
|
230
205
|
let value = params[key];
|
|
231
206
|
// default
|
|
232
|
-
if (rule.default)
|
|
233
|
-
if (type === 'cookie' || type === 'session')
|
|
207
|
+
if (rule.default)
|
|
208
|
+
if (type === 'cookie' || type === 'session')
|
|
234
209
|
this.logger.warn('Cookie and Session not support default rule.');
|
|
235
|
-
}
|
|
236
210
|
else if (typeof value === 'undefined' && rule.default) {
|
|
237
211
|
value = typeof rule.default === 'function' ? rule.default(this.request) : rule.default;
|
|
238
212
|
params[key] = value;
|
|
239
213
|
}
|
|
240
|
-
}
|
|
241
214
|
// required
|
|
242
|
-
if (rule.required
|
|
215
|
+
if (rule.required)
|
|
243
216
|
if (typeof value === 'undefined' || value === null) {
|
|
244
217
|
const error = Error(`[${type}] ${baseKey}${key} is required.`);
|
|
245
218
|
if (config.onError) {
|
|
246
219
|
const res = config.onError(`${type}.rule.required`, `${baseKey}${key}`, value);
|
|
247
|
-
if (res)
|
|
248
|
-
throw new
|
|
249
|
-
}
|
|
220
|
+
if (res)
|
|
221
|
+
throw new HttpError(res);
|
|
250
222
|
}
|
|
251
223
|
throw error;
|
|
252
224
|
}
|
|
253
|
-
}
|
|
254
225
|
if (typeof value !== 'undefined' && value !== null) {
|
|
255
226
|
// type
|
|
256
|
-
if (rule.type)
|
|
257
|
-
if (type === 'cookie')
|
|
227
|
+
if (rule.type)
|
|
228
|
+
if (type === 'cookie')
|
|
258
229
|
this.logger.warn('Cookie not support type rule');
|
|
259
|
-
}
|
|
260
230
|
else {
|
|
261
231
|
let typed = true;
|
|
262
232
|
switch (rule.type) {
|
|
@@ -274,43 +244,33 @@ class Validator {
|
|
|
274
244
|
const error = Error(`[${type}] ${baseKey}${key} must be a ${rule.type}.`);
|
|
275
245
|
if (config.onError) {
|
|
276
246
|
const res = config.onError(`${type}.rule.type`, `${baseKey}${key}`, value);
|
|
277
|
-
if (res)
|
|
278
|
-
throw new
|
|
279
|
-
}
|
|
247
|
+
if (res)
|
|
248
|
+
throw new HttpError(res);
|
|
280
249
|
}
|
|
281
250
|
throw error;
|
|
282
251
|
}
|
|
283
252
|
}
|
|
284
|
-
}
|
|
285
253
|
// in
|
|
286
|
-
if (rule.in && !rule.in.includes(value)) {
|
|
254
|
+
if ((rule.in) && !rule.in.includes(value)) {
|
|
287
255
|
const error = Error(`[${type}] ${baseKey}${key} must be in ${rule.in.join(', ')}.`);
|
|
288
256
|
if (config.onError) {
|
|
289
257
|
const res = config.onError(`${type}.rule.in`, `${baseKey}${key}`, value);
|
|
290
|
-
if (res)
|
|
291
|
-
throw new
|
|
292
|
-
}
|
|
258
|
+
if (res)
|
|
259
|
+
throw new HttpError(res);
|
|
293
260
|
}
|
|
294
261
|
throw error;
|
|
295
262
|
}
|
|
296
263
|
// nest config
|
|
297
|
-
if (rule.config)
|
|
298
|
-
if (type === 'cookie')
|
|
264
|
+
if (rule.config)
|
|
265
|
+
if (type === 'cookie')
|
|
299
266
|
this.logger.warn('Cookie not support nest rule.');
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
}
|
|
308
|
-
else if (typeof value === 'object') {
|
|
309
|
-
// object
|
|
310
|
-
this.validContent(type, value, (baseKey ? `${baseKey}.${key}.` : `${key}.`), rule.config);
|
|
311
|
-
}
|
|
312
|
-
}
|
|
313
|
-
}
|
|
267
|
+
else if (Array.isArray(value))
|
|
268
|
+
// array
|
|
269
|
+
for (const val of value)
|
|
270
|
+
this.validContent(type, val, (baseKey ? `${baseKey}.${key}.` : `${key}.`), rule.config);
|
|
271
|
+
else if (typeof value === 'object')
|
|
272
|
+
// object
|
|
273
|
+
this.validContent(type, value, (baseKey ? `${baseKey}.${key}.` : `${key}.`), rule.config);
|
|
314
274
|
}
|
|
315
275
|
}
|
|
316
276
|
}
|
|
@@ -326,12 +286,26 @@ const ContentType = {
|
|
|
326
286
|
json: 'application/json',
|
|
327
287
|
jsonp: 'application/javascript'
|
|
328
288
|
};
|
|
289
|
+
class HttpError extends Error {
|
|
290
|
+
constructor({ statusCode, message }) {
|
|
291
|
+
super(message);
|
|
292
|
+
if (Error.captureStackTrace)
|
|
293
|
+
Error.captureStackTrace(this, HttpError);
|
|
294
|
+
this.statusCode = statusCode || 500;
|
|
295
|
+
this.message = message;
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
const Name = 'http';
|
|
329
299
|
class Http {
|
|
330
300
|
/**
|
|
331
301
|
* 创建 Http 插件实例
|
|
332
302
|
* @param config {object} 配置项
|
|
333
303
|
* @param config.name {string} 配置名
|
|
334
304
|
* @param config.config {object} 网关配置
|
|
305
|
+
* @param config.config.method {string} 请求方法,默认为 POST
|
|
306
|
+
* @param config.config.path {string} 请求路径,默认为云函数文件路径
|
|
307
|
+
* @param config.config.ignorePathPrefix {string} 排除的路径前缀,当设置 path 时无效
|
|
308
|
+
* @param config.config.cookie {object} Cookie 配置
|
|
335
309
|
* @param config.validator {object} 入参校验配置
|
|
336
310
|
* @param config.validator.params {object} params 校验配置
|
|
337
311
|
* @param config.validator.params.whitelist {string} 白名单配置
|
|
@@ -345,56 +319,66 @@ class Http {
|
|
|
345
319
|
* @param config.validator.session.whitelist {string} 白名单配置
|
|
346
320
|
* @param config.validator.session.onError {function} 自定义报错
|
|
347
321
|
* @param config.validator.session.rules {object} 参数校验规则
|
|
322
|
+
* @param config.validator.before {function} 参数校验前自定义函数
|
|
348
323
|
*/
|
|
349
|
-
constructor(config
|
|
350
|
-
this.
|
|
351
|
-
this.
|
|
352
|
-
this.name = config.name;
|
|
353
|
-
this.config = config.config || Object.create(null);
|
|
354
|
-
if (config.validator)
|
|
324
|
+
constructor(config) {
|
|
325
|
+
this.type = Name;
|
|
326
|
+
this.name = Name;
|
|
327
|
+
this.name = (config === null || config === void 0 ? void 0 : config.name) || this.type;
|
|
328
|
+
this.config = ((config === null || config === void 0 ? void 0 : config.config)) || Object.create(null);
|
|
329
|
+
if ((config === null || config === void 0 ? void 0 : config.validator))
|
|
355
330
|
this.validatorOptions = config.validator;
|
|
356
|
-
|
|
331
|
+
this.logger = new Logger(this.name);
|
|
357
332
|
this.headers = Object.create(null);
|
|
358
333
|
this.cookie = new Cookie(this.config.cookie || {});
|
|
359
334
|
this.session = this.cookie.session;
|
|
360
335
|
}
|
|
361
336
|
async onDeploy(data, next) {
|
|
337
|
+
var _a;
|
|
362
338
|
await next();
|
|
363
|
-
this.logger.debug('
|
|
364
|
-
this.logger.debug('%
|
|
365
|
-
const config =
|
|
339
|
+
this.logger.debug('组装网关配置');
|
|
340
|
+
this.logger.debug('%j', data);
|
|
341
|
+
const config = data.config.plugins ?
|
|
342
|
+
deepMerge(data.config.plugins[this.name || this.type], { config: this.config }) :
|
|
343
|
+
{ config: this.config };
|
|
366
344
|
// 根据文件及文件夹名生成路径
|
|
367
|
-
config.config.path
|
|
368
|
-
|
|
345
|
+
if (!config.config.path) {
|
|
346
|
+
config.config.path = '/' + ((_a = data.name) === null || _a === void 0 ? void 0 : _a.replace(/_/g, '/').replace(/\/index$/, ''));
|
|
347
|
+
if (config.config.path === '/index')
|
|
348
|
+
config.config.path = '/';
|
|
349
|
+
if (config.config.ignorePathPrefix) {
|
|
350
|
+
config.config.path = config.config.path.replace(new RegExp('^' + config.config.ignorePathPrefix), '');
|
|
351
|
+
if (config.config.path === '')
|
|
352
|
+
config.config.path = '/';
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
this.logger.debug('组装完成 %j', config);
|
|
369
356
|
// 引用服务商部署插件
|
|
370
|
-
// eslint-disable-next-line
|
|
371
|
-
const Provider = require(config.provider.type);
|
|
357
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
358
|
+
const Provider = require(config.provider.type).Provider;
|
|
372
359
|
const provider = new Provider(config.provider.config);
|
|
373
360
|
// 部署网关
|
|
374
361
|
await provider.deploy(this.type, data, config);
|
|
375
362
|
}
|
|
376
363
|
async onMount(data, next) {
|
|
377
364
|
this.logger.debug('[onMount] merge config');
|
|
378
|
-
if (data.config.plugins[this.name || this.type])
|
|
365
|
+
if (data.config.plugins && data.config.plugins[this.name || this.type])
|
|
379
366
|
this.config = deepMerge(this.config, data.config.plugins[this.name || this.type].config);
|
|
380
|
-
}
|
|
381
367
|
this.logger.debug('[onMount] prepare cookie & session');
|
|
382
368
|
this.cookie = new Cookie(this.config.cookie || {});
|
|
383
369
|
this.session = this.cookie.session;
|
|
384
370
|
if (this.validatorOptions) {
|
|
385
371
|
this.logger.debug('[onMount] prepare validator');
|
|
386
|
-
this.validator = new Validator(this.validatorOptions);
|
|
372
|
+
this.validator = new Validator(this.validatorOptions, this.logger);
|
|
387
373
|
}
|
|
388
374
|
await next();
|
|
389
375
|
}
|
|
390
376
|
async onInvoke(data, next) {
|
|
391
|
-
|
|
392
|
-
this.logger.time('http');
|
|
377
|
+
var _a, _b;
|
|
393
378
|
this.headers = data.event.headers || Object.create(null);
|
|
379
|
+
this.body = data.event.body;
|
|
394
380
|
this.params = Object.create(null);
|
|
395
|
-
this.response = {
|
|
396
|
-
headers: Object.create(null)
|
|
397
|
-
};
|
|
381
|
+
this.response = { headers: Object.create(null) };
|
|
398
382
|
if (data.event.body) {
|
|
399
383
|
if (data.event.headers && data.event.headers['content-type'] && data.event.headers['content-type'].includes('application/json')) {
|
|
400
384
|
this.logger.debug('[onInvoke] Parse params from json body');
|
|
@@ -404,19 +388,23 @@ class Http {
|
|
|
404
388
|
this.logger.debug('[onInvoke] Parse params from raw body');
|
|
405
389
|
this.params = data.event.body;
|
|
406
390
|
}
|
|
391
|
+
this.logger.debug('[onInvoke] Params: %j', this.params);
|
|
407
392
|
}
|
|
408
393
|
else if (data.event.queryString) {
|
|
409
394
|
this.logger.debug('[onInvoke] Parse params from queryString');
|
|
410
395
|
this.params = data.event.queryString;
|
|
396
|
+
this.logger.debug('[onInvoke] Params: %j', this.params);
|
|
397
|
+
}
|
|
398
|
+
this.cookie.invoke(this.headers.cookie);
|
|
399
|
+
if (this.headers.cookie) {
|
|
400
|
+
this.logger.debug('[onInvoke] Cookie: %j', this.cookie.content);
|
|
401
|
+
this.logger.debug('[onInvoke] Session: %j', this.session.content);
|
|
411
402
|
}
|
|
412
|
-
this.logger.debug('[onInvoke] Parse cookie');
|
|
413
|
-
this.cookie.invoke(this.headers['cookie']);
|
|
414
|
-
this.logger.debug('[onInvoke] Cookie: %o', this.cookie.content);
|
|
415
|
-
this.logger.debug('[onInvoke] Session: %o', this.session.content);
|
|
416
403
|
if (this.validator) {
|
|
417
404
|
this.logger.debug('[onInvoke] Valid request');
|
|
418
405
|
try {
|
|
419
|
-
this.validator.valid({
|
|
406
|
+
await this.validator.valid({
|
|
407
|
+
headers: this.headers,
|
|
420
408
|
params: this.params,
|
|
421
409
|
cookie: this.cookie,
|
|
422
410
|
session: this.session
|
|
@@ -426,53 +414,85 @@ class Http {
|
|
|
426
414
|
this.logger.error(error);
|
|
427
415
|
data.response = {
|
|
428
416
|
statusCode: error.statusCode || 500,
|
|
429
|
-
headers:
|
|
430
|
-
|
|
431
|
-
'X-Request-Id': data.context.request_id
|
|
432
|
-
}, error.headers || {}),
|
|
433
|
-
body: JSON.stringify({
|
|
434
|
-
error: {
|
|
435
|
-
message: error.message
|
|
436
|
-
}
|
|
437
|
-
})
|
|
417
|
+
headers: { 'Content-Type': 'application/json; charset=utf-8' },
|
|
418
|
+
body: JSON.stringify({ error: { message: error.message } })
|
|
438
419
|
};
|
|
439
420
|
return;
|
|
440
421
|
}
|
|
441
422
|
}
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
423
|
+
try {
|
|
424
|
+
await next();
|
|
425
|
+
}
|
|
426
|
+
catch (error) {
|
|
427
|
+
data.response = error;
|
|
428
|
+
}
|
|
429
|
+
// update session
|
|
447
430
|
this.session.update();
|
|
448
431
|
// 处理 body
|
|
449
|
-
if (data.response)
|
|
450
|
-
if (data.response instanceof Error || (data.response.constructor
|
|
432
|
+
if (data.response)
|
|
433
|
+
if (data.response instanceof Error || ((_a = data.response.constructor) === null || _a === void 0 ? void 0 : _a.name) === 'Error') {
|
|
451
434
|
// 当结果是错误类型时
|
|
452
435
|
this.logger.error(data.response);
|
|
453
436
|
this.response.body = JSON.stringify({ error: { message: data.response.message } });
|
|
454
|
-
|
|
437
|
+
try {
|
|
438
|
+
this.response.statusCode = data.response.statusCode || 500;
|
|
439
|
+
}
|
|
440
|
+
catch (error) {
|
|
441
|
+
this.response.statusCode = 500;
|
|
442
|
+
}
|
|
455
443
|
}
|
|
456
|
-
else if (Object.prototype.toString.call(data.response) === '[object Object]' && data.response.statusCode && data.response.headers)
|
|
444
|
+
else if (Object.prototype.toString.call(data.response) === '[object Object]' && data.response.statusCode && data.response.headers)
|
|
457
445
|
// 当返回结果是响应结构体时
|
|
458
446
|
this.response = data.response;
|
|
459
|
-
|
|
460
|
-
else {
|
|
447
|
+
else
|
|
461
448
|
this.response.body = JSON.stringify({ data: data.response });
|
|
462
|
-
}
|
|
463
|
-
}
|
|
464
449
|
// 处理 statusCode
|
|
465
|
-
if (!this.response.statusCode)
|
|
450
|
+
if (!this.response.statusCode)
|
|
466
451
|
this.response.statusCode = this.response.body ? 200 : 201;
|
|
467
|
-
}
|
|
468
452
|
// 处理 headers
|
|
469
453
|
this.response.headers = Object.assign({
|
|
470
454
|
'Content-Type': 'application/json; charset=utf-8',
|
|
471
|
-
'
|
|
455
|
+
'Cache-Control': 'no-cache, no-store'
|
|
472
456
|
}, this.cookie.headers(), this.response.headers);
|
|
473
|
-
/* eslint-disable-next-line require-atomic-updates */
|
|
474
457
|
data.response = this.response;
|
|
475
|
-
|
|
458
|
+
if (process.env.FaasMode === 'local') {
|
|
459
|
+
this.logger.debug('[onInvoke] Response: %j', data.response);
|
|
460
|
+
return;
|
|
461
|
+
}
|
|
462
|
+
// 判断是否需要压缩
|
|
463
|
+
if (data.response.isBase64Encoded ||
|
|
464
|
+
typeof data.response.body !== 'string' ||
|
|
465
|
+
!((_b = data.response.headers['Content-Type']) === null || _b === void 0 ? void 0 : _b.includes('json')) ||
|
|
466
|
+
data.response.body.length < 100)
|
|
467
|
+
return;
|
|
468
|
+
const acceptEncoding = this.headers['accept-encoding'] || this.headers['Accept-Encoding'];
|
|
469
|
+
if (!acceptEncoding || !/(br|gzip|deflate)/.test(acceptEncoding))
|
|
470
|
+
return;
|
|
471
|
+
const originBody = data.response.body;
|
|
472
|
+
try {
|
|
473
|
+
if (acceptEncoding.includes('br')) {
|
|
474
|
+
data.response.headers['Content-Encoding'] = 'br';
|
|
475
|
+
data.response.body = brotliCompressSync(originBody).toString('base64');
|
|
476
|
+
}
|
|
477
|
+
else if (acceptEncoding.includes('gzip')) {
|
|
478
|
+
data.response.headers['Content-Encoding'] = 'gzip';
|
|
479
|
+
data.response.body = gzipSync(originBody).toString('base64');
|
|
480
|
+
}
|
|
481
|
+
else if (acceptEncoding.includes('deflate')) {
|
|
482
|
+
data.response.headers['Content-Encoding'] = 'deflate';
|
|
483
|
+
data.response.body = deflateSync(originBody).toString('base64');
|
|
484
|
+
}
|
|
485
|
+
else
|
|
486
|
+
throw Error('No matched compression.');
|
|
487
|
+
data.response.isBase64Encoded = true;
|
|
488
|
+
data.response.originBody = originBody;
|
|
489
|
+
}
|
|
490
|
+
catch (error) {
|
|
491
|
+
console.error(error);
|
|
492
|
+
// 若压缩失败还原
|
|
493
|
+
data.response.body = originBody;
|
|
494
|
+
delete data.response.headers['Content-Encoding'];
|
|
495
|
+
}
|
|
476
496
|
}
|
|
477
497
|
/**
|
|
478
498
|
* 设置 header
|
|
@@ -489,12 +509,10 @@ class Http {
|
|
|
489
509
|
* @param charset {string} 编码
|
|
490
510
|
*/
|
|
491
511
|
setContentType(type, charset = 'utf-8') {
|
|
492
|
-
if (ContentType[type])
|
|
512
|
+
if (ContentType[type])
|
|
493
513
|
this.setHeader('Content-Type', `${ContentType[type]}; charset=${charset}`);
|
|
494
|
-
|
|
495
|
-
else {
|
|
514
|
+
else
|
|
496
515
|
this.setHeader('Content-Type', `${type}; charset=${charset}`);
|
|
497
|
-
}
|
|
498
516
|
return this;
|
|
499
517
|
}
|
|
500
518
|
/**
|
|
@@ -513,6 +531,9 @@ class Http {
|
|
|
513
531
|
this.response.body = body;
|
|
514
532
|
return this;
|
|
515
533
|
}
|
|
534
|
+
}
|
|
535
|
+
function useHttp(config) {
|
|
536
|
+
return usePlugin(new Http(config));
|
|
516
537
|
}
|
|
517
538
|
|
|
518
|
-
export { ContentType, Cookie, Http, Session, Validator };
|
|
539
|
+
export { ContentType, Cookie, Http, HttpError, Session, Validator, useHttp };
|