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