Repository navigation
Expand file tree
/
Copy pathproxy.js
More file actions
119 lines (104 loc) · 4.2 KB
/
Copy pathproxy.js
File metadata and controls
119 lines (104 loc) · 4.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
/**
* @file 请求代理
* 数据的解压与压缩。client->server:accept-encoding: gzip, deflate, br 表示支持的压缩方式
* server->client: content-encoding: gzip。表示服务器使用的压缩方式。Tomcat 开启Gzip
* client接收到之后自己去解压
*/
'use strict';
let url = require('url');
let https = require('https');
let http = require('http');
let querystring = require('querystring');
let zlib = require('zlib');
let API_PROXY = require('../config/apiProxy');
/**
* 接口请求代理,代理接口的地址为: `/api/:key`
* 给`/api/:key`请求的参数、body以及header信息,会转发给被代理的最终的接口。
*/
module.exports = function (req, res, next) {
let key = req.params.key;
let urlObj = url.parse(API_PROXY[key] || '');
let origin = url.parse(req.url);
let originQuery = origin.query;
let body = req.body;
let postData = '';
let hasQuery = !!urlObj.query;
if (!(key in API_PROXY)) {
return res.json({
status: 1000,
message: '请求的接口不存在'
});
}
// 处理query参数,将请求的参数追加到最终代理接口上
if (originQuery) {
urlObj.path += (hasQuery ? '&' : '?') + originQuery;
urlObj.query = hasQuery ? urlObj.query + '&' + originQuery : originQuery;
urlObj.href += (hasQuery ? '&' : '?') + originQuery;
}
urlObj.headers = req.headers;
urlObj.method = req.method;
urlObj.headers.host = urlObj.host;
// 处理POST数据的body
if (req.method === 'POST') {
if (req.headers['content-type'] === 'application/json') {
postData = JSON.stringify(body);
} else {
postData = querystring.stringify(body);
}
}
// 纠正content-length,如果是 **body带有汉字的** ,取length不是取的字节,导致传给服务器的body解析出错
if (postData && 'content-length' in urlObj.headers) {
urlObj.headers['content-length'] = Buffer.byteLength(postData);
}
/**
* 创建urlObj的请求。
* 请求到数据之后,保存在日志中,gzip压缩的需要解压,输出正常日志
* 将response.pipe(res)
*/
let client = urlObj.protocol === 'https:' ? https : http; // 获取请求协议
let proxy = client.request(urlObj, function (response) {
res.status(response.statusCode);
res.set(response.headers);
response.pipe(res); // response => res
let contentType = response.headers['content-type'];
let encoding = response.headers['content-encoding']; // 获取服务器的压缩方式
let canUnZip = encoding === 'gzip' || encoding === 'deflate';
let isTextFile = /(text|xml|html|plain|json|javascript|css)/.test(contentType);
let _data = '';
// 开启了服务器压缩模式,需要进行压缩数据的pipe传输,保证日志_data输出不乱码
if (canUnZip && isTextFile) {
let unzipStream = encoding === 'gzip' ? zlib.createUnzip() : zlib.createInflate();
unzipStream.on('data', function (chunk) {
_data += chunk;
});
response.pipe(unzipStream).on('end', logAPI);
} else {
// 未开启服务器压缩模式,只需要直接拼接数据即可
response.on('data', function (data) {
_data += data.toString();
});
// 响应结束之后,在日志中收集_data
response.on('end', logAPI);
}
function logAPI () {
console.info('接口代理请求完成,请求信息:', JSON.stringify(urlObj), '状态:', response.statusCode, '请求参数: ', postData, '响应的数据:', _data);
}
});
if (req.method === 'POST') {
proxy.write(postData);
}
/**
* 请求关闭,关闭链接
*/
res.on('close', function () {
proxy.abort();
});
proxy.end();
proxy.on('error', function (err) {
console.error('接口代理请求失败,请求信息:', JSON.stringify(urlObj), '请求参数: ', postData, '错误信息:', err);
res.json({
status: 1001,
message: '网络繁忙,请稍后再试'
});
});
};