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