@faasjs/http 0.0.2-beta.26 → 0.0.2-beta.260
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/lib/cookie.d.ts +7 -11
- package/lib/index.d.ts +56 -31
- package/lib/index.es.js +174 -140
- package/lib/index.js +178 -144
- package/lib/session.d.ts +14 -13
- package/lib/validator.d.ts +35 -19
- package/package.json +9 -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');
|
|
@@ -71,26 +69,23 @@ class Session {
|
|
|
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)
|
|
102
|
+
if (cookie)
|
|
108
103
|
cookie.split(';').map((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,61 @@ 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
154
|
constructor(config) {
|
|
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 = new logger.Logger('Http.Validator');
|
|
183
160
|
}
|
|
184
|
-
valid(
|
|
185
|
-
this.request = {
|
|
186
|
-
params,
|
|
187
|
-
cookie,
|
|
188
|
-
session
|
|
189
|
-
};
|
|
161
|
+
async valid(request) {
|
|
190
162
|
this.logger.debug('Begin');
|
|
191
|
-
if (this.
|
|
163
|
+
if (this.before) {
|
|
164
|
+
const result = await this.before(request);
|
|
165
|
+
if (result)
|
|
166
|
+
throw new HttpError(result);
|
|
167
|
+
}
|
|
168
|
+
this.request = request;
|
|
169
|
+
if (this.paramsConfig && request.params) {
|
|
192
170
|
this.logger.debug('Valid params');
|
|
193
|
-
this.validContent('params', params, '', this.paramsConfig);
|
|
171
|
+
this.validContent('params', request.params, '', this.paramsConfig);
|
|
194
172
|
}
|
|
195
|
-
if (this.cookieConfig) {
|
|
173
|
+
if (this.cookieConfig && request.cookie) {
|
|
196
174
|
this.logger.debug('Valid cookie');
|
|
197
|
-
if (
|
|
175
|
+
if (request.cookie == null)
|
|
198
176
|
throw Error('Not found Cookie');
|
|
199
|
-
|
|
200
|
-
this.validContent('cookie', cookie.content, '', this.cookieConfig);
|
|
177
|
+
this.validContent('cookie', request.cookie.content, '', this.cookieConfig);
|
|
201
178
|
}
|
|
202
|
-
if (this.sessionConfig) {
|
|
179
|
+
if (this.sessionConfig && request.session) {
|
|
203
180
|
this.logger.debug('Valid Session');
|
|
204
|
-
if (
|
|
181
|
+
if (request.session == null)
|
|
205
182
|
throw Error('Not found Session');
|
|
206
|
-
|
|
207
|
-
this.validContent('session', session.content, '', this.sessionConfig);
|
|
183
|
+
this.validContent('session', request.session.content, '', this.sessionConfig);
|
|
208
184
|
}
|
|
209
185
|
}
|
|
210
186
|
validContent(type, params, baseKey, config) {
|
|
@@ -212,57 +188,50 @@ class Validator {
|
|
|
212
188
|
const paramsKeys = Object.keys(params);
|
|
213
189
|
const rulesKeys = Object.keys(config.rules);
|
|
214
190
|
const diff = paramsKeys.filter(k => !rulesKeys.includes(k));
|
|
215
|
-
if (diff.length)
|
|
191
|
+
if (diff.length > 0)
|
|
216
192
|
if (config.whitelist === 'error') {
|
|
217
193
|
const diffKeys = diff.map(k => `${baseKey}${k}`);
|
|
218
194
|
const error = Error(`[${type}] Unpermitted keys: ${diffKeys.join(', ')}`);
|
|
219
195
|
if (config.onError) {
|
|
220
196
|
const res = config.onError(`${type}.whitelist`, baseKey, diffKeys);
|
|
221
|
-
if (res)
|
|
222
|
-
throw new
|
|
223
|
-
}
|
|
197
|
+
if (res)
|
|
198
|
+
throw new HttpError(res);
|
|
224
199
|
}
|
|
225
200
|
throw error;
|
|
226
201
|
}
|
|
227
|
-
else if (config.whitelist === 'ignore')
|
|
228
|
-
for (const key of diff)
|
|
202
|
+
else if (config.whitelist === 'ignore')
|
|
203
|
+
for (const key of diff)
|
|
229
204
|
delete params[key];
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
205
|
}
|
|
234
206
|
for (const key in config.rules) {
|
|
235
207
|
const rule = config.rules[key];
|
|
208
|
+
if (!rule)
|
|
209
|
+
continue;
|
|
236
210
|
let value = params[key];
|
|
237
211
|
// default
|
|
238
|
-
if (rule.default)
|
|
239
|
-
if (type === 'cookie' || type === 'session')
|
|
212
|
+
if (rule.default)
|
|
213
|
+
if (type === 'cookie' || type === 'session')
|
|
240
214
|
this.logger.warn('Cookie and Session not support default rule.');
|
|
241
|
-
}
|
|
242
215
|
else if (typeof value === 'undefined' && rule.default) {
|
|
243
216
|
value = typeof rule.default === 'function' ? rule.default(this.request) : rule.default;
|
|
244
217
|
params[key] = value;
|
|
245
218
|
}
|
|
246
|
-
}
|
|
247
219
|
// required
|
|
248
|
-
if (rule.required
|
|
220
|
+
if (rule.required)
|
|
249
221
|
if (typeof value === 'undefined' || value === null) {
|
|
250
222
|
const error = Error(`[${type}] ${baseKey}${key} is required.`);
|
|
251
223
|
if (config.onError) {
|
|
252
224
|
const res = config.onError(`${type}.rule.required`, `${baseKey}${key}`, value);
|
|
253
|
-
if (res)
|
|
254
|
-
throw new
|
|
255
|
-
}
|
|
225
|
+
if (res)
|
|
226
|
+
throw new HttpError(res);
|
|
256
227
|
}
|
|
257
228
|
throw error;
|
|
258
229
|
}
|
|
259
|
-
}
|
|
260
230
|
if (typeof value !== 'undefined' && value !== null) {
|
|
261
231
|
// type
|
|
262
|
-
if (rule.type)
|
|
263
|
-
if (type === 'cookie')
|
|
232
|
+
if (rule.type)
|
|
233
|
+
if (type === 'cookie')
|
|
264
234
|
this.logger.warn('Cookie not support type rule');
|
|
265
|
-
}
|
|
266
235
|
else {
|
|
267
236
|
let typed = true;
|
|
268
237
|
switch (rule.type) {
|
|
@@ -280,43 +249,33 @@ class Validator {
|
|
|
280
249
|
const error = Error(`[${type}] ${baseKey}${key} must be a ${rule.type}.`);
|
|
281
250
|
if (config.onError) {
|
|
282
251
|
const res = config.onError(`${type}.rule.type`, `${baseKey}${key}`, value);
|
|
283
|
-
if (res)
|
|
284
|
-
throw new
|
|
285
|
-
}
|
|
252
|
+
if (res)
|
|
253
|
+
throw new HttpError(res);
|
|
286
254
|
}
|
|
287
255
|
throw error;
|
|
288
256
|
}
|
|
289
257
|
}
|
|
290
|
-
}
|
|
291
258
|
// in
|
|
292
|
-
if (rule.in && !rule.in.includes(value)) {
|
|
259
|
+
if ((rule.in) && !rule.in.includes(value)) {
|
|
293
260
|
const error = Error(`[${type}] ${baseKey}${key} must be in ${rule.in.join(', ')}.`);
|
|
294
261
|
if (config.onError) {
|
|
295
262
|
const res = config.onError(`${type}.rule.in`, `${baseKey}${key}`, value);
|
|
296
|
-
if (res)
|
|
297
|
-
throw new
|
|
298
|
-
}
|
|
263
|
+
if (res)
|
|
264
|
+
throw new HttpError(res);
|
|
299
265
|
}
|
|
300
266
|
throw error;
|
|
301
267
|
}
|
|
302
268
|
// nest config
|
|
303
|
-
if (rule.config)
|
|
304
|
-
if (type === 'cookie')
|
|
269
|
+
if (rule.config)
|
|
270
|
+
if (type === 'cookie')
|
|
305
271
|
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
|
-
}
|
|
272
|
+
else if (Array.isArray(value))
|
|
273
|
+
// array
|
|
274
|
+
for (const val of value)
|
|
275
|
+
this.validContent(type, val, (baseKey ? `${baseKey}.${key}.` : `${key}.`), rule.config);
|
|
276
|
+
else if (typeof value === 'object')
|
|
277
|
+
// object
|
|
278
|
+
this.validContent(type, value, (baseKey ? `${baseKey}.${key}.` : `${key}.`), rule.config);
|
|
320
279
|
}
|
|
321
280
|
}
|
|
322
281
|
}
|
|
@@ -332,12 +291,27 @@ const ContentType = {
|
|
|
332
291
|
json: 'application/json',
|
|
333
292
|
jsonp: 'application/javascript'
|
|
334
293
|
};
|
|
294
|
+
class HttpError extends Error {
|
|
295
|
+
constructor({ statusCode, message }) {
|
|
296
|
+
super(message);
|
|
297
|
+
if (Error.captureStackTrace)
|
|
298
|
+
Error.captureStackTrace(this, HttpError);
|
|
299
|
+
this.statusCode = statusCode || 500;
|
|
300
|
+
this.message = message;
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
const Name = 'http';
|
|
304
|
+
const globals = {};
|
|
335
305
|
class Http {
|
|
336
306
|
/**
|
|
337
307
|
* 创建 Http 插件实例
|
|
338
308
|
* @param config {object} 配置项
|
|
339
309
|
* @param config.name {string} 配置名
|
|
340
310
|
* @param config.config {object} 网关配置
|
|
311
|
+
* @param config.config.method {string} 请求方法,默认为 POST
|
|
312
|
+
* @param config.config.path {string} 请求路径,默认为云函数文件路径
|
|
313
|
+
* @param config.config.ignorePathPrefix {string} 排除的路径前缀,当设置 path 时无效
|
|
314
|
+
* @param config.config.cookie {object} Cookie 配置
|
|
341
315
|
* @param config.validator {object} 入参校验配置
|
|
342
316
|
* @param config.validator.params {object} params 校验配置
|
|
343
317
|
* @param config.validator.params.whitelist {string} 白名单配置
|
|
@@ -351,37 +325,51 @@ class Http {
|
|
|
351
325
|
* @param config.validator.session.whitelist {string} 白名单配置
|
|
352
326
|
* @param config.validator.session.onError {function} 自定义报错
|
|
353
327
|
* @param config.validator.session.rules {object} 参数校验规则
|
|
328
|
+
* @param config.validator.before {function} 参数校验前自定义函数
|
|
354
329
|
*/
|
|
355
|
-
constructor(config
|
|
356
|
-
this.
|
|
357
|
-
this.
|
|
358
|
-
this.name = config.name;
|
|
359
|
-
this.config = config.config || Object.create(null);
|
|
360
|
-
if (config.validator)
|
|
330
|
+
constructor(config) {
|
|
331
|
+
this.type = Name;
|
|
332
|
+
this.name = Name;
|
|
333
|
+
this.name = (config === null || config === void 0 ? void 0 : config.name) || this.type;
|
|
334
|
+
this.config = ((config === null || config === void 0 ? void 0 : config.config)) || Object.create(null);
|
|
335
|
+
if ((config === null || config === void 0 ? void 0 : config.validator))
|
|
361
336
|
this.validatorOptions = config.validator;
|
|
337
|
+
this.logger = new logger.Logger(this.name);
|
|
362
338
|
this.headers = Object.create(null);
|
|
363
339
|
this.cookie = new Cookie(this.config.cookie || {});
|
|
364
340
|
this.session = this.cookie.session;
|
|
365
341
|
}
|
|
366
342
|
async onDeploy(data, next) {
|
|
343
|
+
var _a;
|
|
367
344
|
await next();
|
|
368
|
-
this.logger.debug('
|
|
345
|
+
this.logger.debug('组装网关配置');
|
|
369
346
|
this.logger.debug('%o', data);
|
|
370
|
-
const config =
|
|
347
|
+
const config = data.config.plugins ?
|
|
348
|
+
deep_merge.deepMerge(data.config.plugins[this.name || this.type], { config: this.config }) :
|
|
349
|
+
{ config: this.config };
|
|
371
350
|
// 根据文件及文件夹名生成路径
|
|
372
|
-
config.config.path
|
|
373
|
-
|
|
351
|
+
if (!config.config.path) {
|
|
352
|
+
config.config.path = '=/' + ((_a = data.name) === null || _a === void 0 ? void 0 : _a.replace(/_/g, '/').replace(/\/index$/, ''));
|
|
353
|
+
if (config.config.path === '=/index')
|
|
354
|
+
config.config.path = '=/';
|
|
355
|
+
if (config.config.ignorePathPrefix) {
|
|
356
|
+
config.config.path = config.config.path.replace(new RegExp('^=' + config.config.ignorePathPrefix), '=');
|
|
357
|
+
if (config.config.path === '=')
|
|
358
|
+
config.config.path = '=/';
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
this.logger.debug('组装完成 %o', config);
|
|
374
362
|
// 引用服务商部署插件
|
|
375
|
-
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
376
|
-
const Provider = require(config.provider.type);
|
|
363
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
364
|
+
const Provider = require(config.provider.type).Provider;
|
|
377
365
|
const provider = new Provider(config.provider.config);
|
|
378
366
|
// 部署网关
|
|
379
367
|
await provider.deploy(this.type, data, config);
|
|
380
368
|
}
|
|
381
369
|
async onMount(data, next) {
|
|
382
370
|
this.logger.debug('[onMount] merge config');
|
|
383
|
-
if (data.config.plugins[this.name || this.type])
|
|
384
|
-
this.config = deepMerge(this.config, data.config.plugins[this.name || this.type].config);
|
|
371
|
+
if (data.config.plugins && data.config.plugins[this.name || this.type])
|
|
372
|
+
this.config = deep_merge.deepMerge(this.config, data.config.plugins[this.name || this.type].config);
|
|
385
373
|
this.logger.debug('[onMount] prepare cookie & session');
|
|
386
374
|
this.cookie = new Cookie(this.config.cookie || {});
|
|
387
375
|
this.session = this.cookie.session;
|
|
@@ -389,11 +377,11 @@ class Http {
|
|
|
389
377
|
this.logger.debug('[onMount] prepare validator');
|
|
390
378
|
this.validator = new Validator(this.validatorOptions);
|
|
391
379
|
}
|
|
380
|
+
globals[this.name] = this;
|
|
392
381
|
await next();
|
|
393
382
|
}
|
|
394
383
|
async onInvoke(data, next) {
|
|
395
|
-
|
|
396
|
-
this.logger.time('http');
|
|
384
|
+
var _a, _b;
|
|
397
385
|
this.headers = data.event.headers || Object.create(null);
|
|
398
386
|
this.params = Object.create(null);
|
|
399
387
|
this.response = { headers: Object.create(null) };
|
|
@@ -410,14 +398,16 @@ class Http {
|
|
|
410
398
|
this.logger.debug('[onInvoke] Parse params from queryString');
|
|
411
399
|
this.params = data.event.queryString;
|
|
412
400
|
}
|
|
401
|
+
this.logger.debug('[onInvoke] Params: %j', this.params);
|
|
413
402
|
this.logger.debug('[onInvoke] Parse cookie');
|
|
414
|
-
this.cookie.invoke(this.headers
|
|
415
|
-
this.logger.debug('[onInvoke] Cookie: %
|
|
416
|
-
this.logger.debug('[onInvoke] Session: %
|
|
417
|
-
if (this.validator) {
|
|
403
|
+
this.cookie.invoke(this.headers.cookie);
|
|
404
|
+
this.logger.debug('[onInvoke] Cookie: %j', this.cookie.content);
|
|
405
|
+
this.logger.debug('[onInvoke] Session: %j', this.session.content);
|
|
406
|
+
if (this.validator && data.event.httpMethod) {
|
|
418
407
|
this.logger.debug('[onInvoke] Valid request');
|
|
419
408
|
try {
|
|
420
|
-
this.validator.valid({
|
|
409
|
+
await this.validator.valid({
|
|
410
|
+
headers: this.headers,
|
|
421
411
|
params: this.params,
|
|
422
412
|
cookie: this.cookie,
|
|
423
413
|
session: this.session
|
|
@@ -427,52 +417,88 @@ class Http {
|
|
|
427
417
|
this.logger.error(error);
|
|
428
418
|
data.response = {
|
|
429
419
|
statusCode: error.statusCode || 500,
|
|
430
|
-
headers:
|
|
420
|
+
headers: {
|
|
431
421
|
'Content-Type': 'application/json; charset=utf-8',
|
|
432
|
-
'X-
|
|
433
|
-
},
|
|
422
|
+
'X-SCF-RequestId': data.context.request_id
|
|
423
|
+
},
|
|
434
424
|
body: JSON.stringify({ error: { message: error.message } })
|
|
435
425
|
};
|
|
436
426
|
return;
|
|
437
427
|
}
|
|
438
428
|
}
|
|
439
|
-
this.logger.timeEnd('http', '[onInvoke] Parse & valid done');
|
|
440
429
|
try {
|
|
441
430
|
await next();
|
|
442
431
|
}
|
|
443
432
|
catch (error) {
|
|
444
433
|
data.response = error;
|
|
445
434
|
}
|
|
446
|
-
this.logger.debug('[onInvoke] Generate response');
|
|
447
|
-
this.logger.time('http');
|
|
448
435
|
// update seesion
|
|
449
436
|
this.session.update();
|
|
450
437
|
// 处理 body
|
|
451
438
|
if (data.response)
|
|
452
|
-
if (data.response instanceof Error || (data.response.constructor
|
|
439
|
+
if (data.response instanceof Error || ((_a = data.response.constructor) === null || _a === void 0 ? void 0 : _a.name) === 'Error') {
|
|
453
440
|
// 当结果是错误类型时
|
|
454
441
|
this.logger.error(data.response);
|
|
455
442
|
this.response.body = JSON.stringify({ error: { message: data.response.message } });
|
|
456
|
-
|
|
443
|
+
try {
|
|
444
|
+
this.response.statusCode = data.response.statusCode || 500;
|
|
445
|
+
}
|
|
446
|
+
catch (error) {
|
|
447
|
+
this.response.statusCode = 500;
|
|
448
|
+
}
|
|
457
449
|
}
|
|
458
|
-
else if (Object.prototype.toString.call(data.response) === '[object Object]' && data.response.statusCode && data.response.headers)
|
|
450
|
+
else if (Object.prototype.toString.call(data.response) === '[object Object]' && data.response.statusCode && data.response.headers)
|
|
459
451
|
// 当返回结果是响应结构体时
|
|
460
452
|
this.response = data.response;
|
|
461
|
-
|
|
462
|
-
else {
|
|
453
|
+
else
|
|
463
454
|
this.response.body = JSON.stringify({ data: data.response });
|
|
464
|
-
}
|
|
465
455
|
// 处理 statusCode
|
|
466
456
|
if (!this.response.statusCode)
|
|
467
457
|
this.response.statusCode = this.response.body ? 200 : 201;
|
|
468
458
|
// 处理 headers
|
|
469
459
|
this.response.headers = Object.assign({
|
|
470
460
|
'Content-Type': 'application/json; charset=utf-8',
|
|
471
|
-
'X-
|
|
461
|
+
'X-SCF-RequestId': data.context.request_id
|
|
472
462
|
}, this.cookie.headers(), this.response.headers);
|
|
473
|
-
/* eslint-disable-next-line require-atomic-updates */
|
|
474
463
|
data.response = this.response;
|
|
475
|
-
|
|
464
|
+
if (process.env.FaasMode === 'local') {
|
|
465
|
+
this.logger.debug('[onInvoke] Response: %j', data.response);
|
|
466
|
+
return;
|
|
467
|
+
}
|
|
468
|
+
// 判断是否需要压缩
|
|
469
|
+
if (data.response.isBase64Encoded ||
|
|
470
|
+
typeof data.response.body !== 'string' ||
|
|
471
|
+
!((_b = data.response.headers['Content-Type']) === null || _b === void 0 ? void 0 : _b.includes('json')) ||
|
|
472
|
+
data.response.body.length < 100)
|
|
473
|
+
return;
|
|
474
|
+
const acceptEncoding = this.headers['accept-encoding'] || this.headers['Accept-Encoding'];
|
|
475
|
+
if (!acceptEncoding || !/(br|gzip|deflate)/.test(acceptEncoding))
|
|
476
|
+
return;
|
|
477
|
+
const originBody = data.response.body;
|
|
478
|
+
try {
|
|
479
|
+
if (acceptEncoding.includes('br')) {
|
|
480
|
+
data.response.headers['Content-Encoding'] = 'br';
|
|
481
|
+
data.response.body = zlib.brotliCompressSync(originBody).toString('base64');
|
|
482
|
+
}
|
|
483
|
+
else if (acceptEncoding.includes('gzip')) {
|
|
484
|
+
data.response.headers['Content-Encoding'] = 'gzip';
|
|
485
|
+
data.response.body = zlib.gzipSync(originBody).toString('base64');
|
|
486
|
+
}
|
|
487
|
+
else if (acceptEncoding.includes('deflate')) {
|
|
488
|
+
data.response.headers['Content-Encoding'] = 'deflate';
|
|
489
|
+
data.response.body = zlib.deflateSync(originBody).toString('base64');
|
|
490
|
+
}
|
|
491
|
+
else
|
|
492
|
+
throw Error('No matched compression.');
|
|
493
|
+
data.response.isBase64Encoded = true;
|
|
494
|
+
data.response.originBody = originBody;
|
|
495
|
+
}
|
|
496
|
+
catch (error) {
|
|
497
|
+
console.error(error);
|
|
498
|
+
// 若压缩失败还原
|
|
499
|
+
data.response.body = originBody;
|
|
500
|
+
delete data.response.headers['Content-Encoding'];
|
|
501
|
+
}
|
|
476
502
|
}
|
|
477
503
|
/**
|
|
478
504
|
* 设置 header
|
|
@@ -511,10 +537,18 @@ class Http {
|
|
|
511
537
|
this.response.body = body;
|
|
512
538
|
return this;
|
|
513
539
|
}
|
|
540
|
+
}
|
|
541
|
+
function useHttp(config) {
|
|
542
|
+
const name = (config === null || config === void 0 ? void 0 : config.name) || Name;
|
|
543
|
+
if (process.env.FaasEnv !== 'testing' && globals[name])
|
|
544
|
+
return func.usePlugin(globals[name]);
|
|
545
|
+
return func.usePlugin(new Http(config));
|
|
514
546
|
}
|
|
515
547
|
|
|
516
548
|
exports.ContentType = ContentType;
|
|
517
549
|
exports.Cookie = Cookie;
|
|
518
550
|
exports.Http = Http;
|
|
551
|
+
exports.HttpError = HttpError;
|
|
519
552
|
exports.Session = Session;
|
|
520
553
|
exports.Validator = Validator;
|
|
554
|
+
exports.useHttp = useHttp;
|
package/lib/session.d.ts
CHANGED
|
@@ -9,10 +9,11 @@ export interface SessionOptions {
|
|
|
9
9
|
digest?: string;
|
|
10
10
|
cipherName?: string;
|
|
11
11
|
}
|
|
12
|
-
export declare
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
12
|
+
export declare type SessionContent = string | number | {
|
|
13
|
+
[key: string]: any;
|
|
14
|
+
} | null | undefined;
|
|
15
|
+
export declare class Session<S, C> {
|
|
16
|
+
content: S;
|
|
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?: SessionContent): Session<S, C>;
|
|
37
|
+
update(): Session<S, C>;
|
|
37
38
|
}
|