catproxy
Version:
a node proxy or host change tools
535 lines (482 loc) • 15.4 kB
JavaScript
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = function (reqInfo, resInfo) {
// /******不要尝试取修改 resInfo的引用,会导致 isBinary取不到***************/
var self = this;
var res = resInfo.res;
var req = reqInfo.req;
var id = (0, _tools.getMonitorId)();
Object.defineProperty(reqInfo, 'id', {
value: id,
enumerable: true
});
Object.defineProperty(resInfo, 'id', {
value: id,
enumerable: true
});
// 当bodyData缓存处理完毕就触发事件告诉用户数据
res.on('resBodyDataReady', function (err, bodyData) {
var headers = res.headers || {};
var result = {};
if (reqInfo.sendToFile) {
Object.defineProperty(result, 'sendToFile', {
writable: false,
value: reqInfo.sendToFile,
enumerable: true
});
}
// 响应回来后所有的字段都是只读的
Object.defineProperties(result, {
headers: {
writable: false,
value: headers,
enumerable: true
},
statusCode: {
writable: false,
value: res.statusCode,
enumerable: true
},
host: {
writable: false,
value: reqInfo.host,
enumerable: true
},
method: {
writable: false,
value: reqInfo.method,
enumerable: true
},
protocol: {
writable: false,
value: reqInfo.protocol,
enumerable: true
},
originalFullUrl: {
writable: false,
value: reqInfo.originalFullUrl,
enumerable: true
},
port: {
writable: false,
value: reqInfo.port,
enumerable: true
},
path: {
writable: false,
value: reqInfo.path,
enumerable: true
},
originalUrl: {
writable: false,
value: reqInfo.originalUrl,
enumerable: true
},
endTime: {
writable: false,
value: new Date().getTime(),
enumerable: true
},
bodyData: {
writable: false,
value: bodyData,
enumerable: true
},
bodyDataErr: {
writable: false,
value: err && err.message ? err.message : err,
enumerable: true
},
id: {
writable: false,
value: id,
enumerable: true
},
isBinary: {
writable: false,
value: resInfo.isBinary,
enumerable: true
}
});
if (resInfo.charset) {
Object.defineProperty(result, 'charset', {
writable: false,
value: resInfo.charset
});
}
return _evt.afterRes.call(self, result);
});
req.on('reqBodyDataReady', function (err, reqBodyData) {
reqInfo.bodyData = reqBodyData || [];
reqInfo.bodyDataErr = err;
// 请求前拦截一次--所有的拦截都在evt.js中处理
_promise2.default.resolve(_evt.beforeReq.call(self, reqInfo)).then(function (result) {
// 引用发生变化
if (result !== reqInfo) {
reqInfo = (0, _merge2.default)(result, reqInfo);
}
Object.defineProperties(resInfo, {
host: {
writable: false,
value: reqInfo.host,
enumerable: true
},
method: {
writable: false,
value: reqInfo.method,
enumerable: true
},
protocol: {
writable: false,
value: reqInfo.protocol,
enumerable: true
},
port: {
writable: false,
value: reqInfo.port,
enumerable: true
},
path: {
writable: false,
value: reqInfo.path,
enumerable: true
}
});
// 将是否设置weinre传递到 resInfo
if (typeof reqInfo.weinre === 'boolean') {
resInfo.weinre = reqInfo.weinre;
delete reqInfo.weinre;
}
return { reqInfo: reqInfo, resInfo: resInfo };
}).then(function (_ref3) {
var reqInfo = _ref3.reqInfo,
resInfo = _ref3.resInfo;
// 如果在事件里面已经结束了请求,那就结束了
if (res.finished) {
// 用户做了转发处理,这个时候不知道内容是什么
res.emit('resBodyDataReady', null, null);
} else if (reqInfo.redirect) {
resInfo.headers = {
Location: reqInfo.redirect
};
resInfo.statusCode = 302;
resInfo.bodyData = '';
triggerBeforeRes.call(self, resInfo).then(function () {
res.writeHead(resInfo.statusCode, resInfo.headers);
res.end();
res.emit('resBodyDataReady', null, null);
}, function () {
var err = '调用内部出现错误';
(0, _tools.sendErr)(res, err, req.url);
res.emit('resBodyDataReady', err, null);
});
} else {
if (reqInfo.sendToFile) {
return local.call(self, reqInfo, resInfo, reqInfo.sendToFile);
} else {
return remote.call(self, reqInfo, resInfo);
}
}
}).then(null, function (err) {
// 日志在 sendErr中打印和处理
(0, _tools.sendErr)(res, err, req.url);
res.emit('resBodyDataReady', err, null);
});
});
};
var _http = require('http');
var _http2 = _interopRequireDefault(_http);
var _https = require('https');
var _https2 = _interopRequireDefault(_https);
var _log = require('./log');
var _log2 = _interopRequireDefault(_log);
var _buffer = require('buffer');
var _fs = require('fs');
var _fs2 = _interopRequireDefault(_fs);
var _merge = require('merge');
var _merge2 = _interopRequireDefault(_merge);
var _defCfg = require('./config/defCfg');
var _promise = require('promise');
var _promise2 = _interopRequireDefault(_promise);
var _changeHost = require('./changeHost');
var _changeHost2 = _interopRequireDefault(_changeHost);
var _ip = require('ip');
var _ip2 = _interopRequireDefault(_ip);
var _getLocalIps = require('./getLocalIps');
var _tools = require('./tools');
var _net = require('net');
var _net2 = _interopRequireDefault(_net);
var _cert = require('./cert/cert.js');
var _mime = require('mime');
var _mime2 = _interopRequireDefault(_mime);
var _path = require('path');
var _path2 = _interopRequireDefault(_path);
var _querystring = require('querystring');
var _querystring2 = _interopRequireDefault(_querystring);
var _config = require('./config/config');
var config = _interopRequireWildcard(_config);
var _evt = require('./evt');
function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var isStartHttps = /https/; // 处理请求来后返回的数据
// 发送代理请求钱触发
var triggerBeforeRes = function triggerBeforeRes(resInfo) {
return _evt.beforeRes.call(this, resInfo).then(function (result) {
return (0, _merge2.default)(resInfo, result);
});
};
// 处理本地数据
var local = function local(reqInfo, resInfo, fileAbsPath) {
var com = this;
resInfo.headers = resInfo.headers || {};
return new _promise2.default(function (resolve) {
_fs2.default.readFile(fileAbsPath, function (err, buffer) {
if (err) {
resInfo.bodyData = new _buffer.Buffer('local file error' + err);
// 如果用户没有设置statusCode就设置默认的
resInfo.statusCode = 404;
resolve(resInfo);
} else {
// 如果用户没有设置statusCode就设置默认的
resInfo.statusCode = 200;
resInfo.bodyData = buffer;
resolve(resInfo);
}
});
}).then(function (resInfo) {
return triggerBeforeRes.call(com, resInfo);
}).then(function (resInfo) {
var bodyData = resInfo.bodyData,
_resInfo$headers = resInfo.headers,
headers = _resInfo$headers === undefined ? {} : _resInfo$headers,
statusCode = resInfo.statusCode,
res = resInfo.res;
headers['loacl-file'] = _querystring2.default.escape(fileAbsPath);
delete headers['content-length'];
delete headers['content-encoding'];
if (!headers['content-type']) {
var extName = _path2.default.extname(fileAbsPath) || '';
var mimeType = extName ? _mime2.default.lookup(extName.slice(1)) : 'text/html';
headers['content-type'] = mimeType;
}
res.writeHead(statusCode, headers || {});
if (!res.headers) {
res.headers = headers || {};
}
res.end(bodyData);
res.emit('resBodyDataReady', null, bodyData);
}, function (err) {
var _resInfo$headers2 = resInfo.headers,
headers = _resInfo$headers2 === undefined ? {} : _resInfo$headers2,
res = resInfo.res;
// 由错误方法删除的header
return _promise2.default.reject(err);
});
};
// 处理将 域名转换成ip
var detailHost = function detailHost(result, reqInfo, resInfo) {
// 取当前启动的port
var com = this;
var _config$get = config.get(),
port = _config$get.port,
httpsPort = _config$get.httpsPort;
var isServerPort = +port === +result.port;
if (isStartHttps.test(reqInfo.protocol)) {
isServerPort = +httpsPort === +result.port;
}
// 这里自己将死循环嗯哼获取ip错误的情况已经处理了
return (0, _changeHost2.default)(result.hostname, isServerPort).then(function (address) {
// 如果还是死循环,则跳出
if (isServerPort && _getLocalIps.localIps.some(function (current) {
return _ip2.default.isEqual(current, address);
})) {
if (reqInfo.headers && reqInfo.headers['self-server']) {
return _promise2.default.reject('Dead circulation');
} else {
reqInfo.headers = reqInfo.headers || {};
reqInfo.headers['self-server'] = 1;
}
}
return (0, _merge2.default)(result, {
hostname: address
});
}, function (err) {
var res = resInfo.res;
return triggerBeforeRes.call(com, (0, _merge2.default)(resInfo, { statusCode: 504 }, { bodyDataErr: err, headers: {} })).then(function () {
return _promise2.default.reject(err);
});
});
};
// 真正代理请求
var proxyReq = function proxyReq(options, reqInfo, resInfo, req) {
var com = this;
return new _promise2.default(function (resolve, reject) {
// 在这里hostname已经全部被转换成 ip了,将ip传递到前端
resInfo.serverIp = options.hostname;
// 发出请求
_log2.default.verbose('send proxy request originalFullUrl: ' + reqInfo.originalFullUrl);
var proxyReq = (isStartHttps.test(reqInfo.protocol) ? _https2.default : _http2.default).request(options, function (proxyRes) {
var remoteUrl = (0, _tools.getUrl)((0, _merge2.default)({}, options, { protocol: reqInfo.protocol }));
_log2.default.verbose('received request from : ' + remoteUrl + ', statusCode ' + proxyRes.statusCode);
resInfo = (0, _merge2.default)(resInfo, {
headers: proxyRes.headers || {},
statusCode: proxyRes.statusCode
});
resolve({ proxyRes: proxyRes, remoteUrl: remoteUrl, reqInfo: reqInfo, resInfo: resInfo });
});
// 向 直接请求写入数据
if (reqInfo.bodyData && reqInfo.bodyData.length) {
if (!reqInfo.bodyDataErr) {
proxyReq.write(reqInfo.bodyData);
proxyReq.end();
} else {
proxyReq.write(reqInfo.bodyData);
req.on('data', function (buffer) {
proxyReq.write(buffer);
}).on('end', function () {
proxyReq.end();
});
req.resume();
}
} else {
// 没有数据就直接end否则读取数据
proxyReq.end();
}
// 出错直接结束请求
proxyReq.on('error', function (err) {
reject(err);
});
}).then(function (_ref) {
var proxyRes = _ref.proxyRes,
remoteUrl = _ref.remoteUrl,
reqInfo = _ref.reqInfo,
resInfo = _ref.resInfo;
var res = resInfo.res;
// 数据太大的时候触发
var err = {
message: '响应数据过大,无法显示',
status: _defCfg.STATUS.LIMIT_ERROR
};
var resBodyData = [],
l = 0,
isError = false,
isFired = false;
proxyRes
// 过滤大文件,只有小文件才返回
// 文件过大的将无法拦截,没有事件通知
.on('data', function (chunk) {
if (l > _defCfg.LIMIT_SIZE) {
isError = true;
if (!isFired) {
isFired = true;
var statusCode = resInfo.statusCode,
headers = resInfo.headers;
headers['remote-url'] = _querystring2.default.escape(remoteUrl);
res.writeHead(statusCode || 200, headers);
res.write(_buffer.Buffer.concat(resBodyData));
res.write(chunk);
resBodyData = [];
var bodyData = null;
var bodyDataErr = err.message;
// 提前触发事件
return triggerBeforeRes.call(com, (0, _merge2.default)(resInfo, { bodyData: bodyData, bodyDataErr: bodyDataErr }));
} else {
res.write(chunk);
}
} else {
resBodyData.push(chunk);
l += chunk.length;
}
}).on('end', function () {
var bodyData = _buffer.Buffer.concat(resBodyData);
return _promise2.default.resolve(bodyData).then(function (bodyData) {
// 文件大小没有出错的情况下
if (!isError) {
return triggerBeforeRes.call(com, (0, _merge2.default)(resInfo, { bodyData: bodyData })).then(function (resInfo) {
var statusCode = resInfo.statusCode,
headers = resInfo.headers,
bodyData = resInfo.bodyData;
headers['remote-url'] = _querystring2.default.escape(remoteUrl);
res.writeHead(statusCode || 200, headers);
res.write(bodyData);
return resInfo;
}, function (err) {
var headers = resInfo.headers;
headers['remote-url'] = _querystring2.default.escape(remoteUrl);
res.writeHead(500, headers);
err = (0, _tools.writeErr)(err);
res.write(err);
_log2.default.error(err);
resInfo.statusCode = 500;
resInfo.bodyData = err;
return resInfo;
});
} else {
resInfo.bodyData = new _buffer.Buffer('');
resInfo.bodyDataErr = err.message;
return resInfo;
}
}).then(function (_ref2) {
var headers = _ref2.headers,
bodyData = _ref2.bodyData;
// 转换head大小写问题
if (!res.headers) {
res.headers = headers;
}
res.end();
res.emit('resBodyDataReady', isError ? err : null, bodyData || new _buffer.Buffer(''));
}, function (err) {
_log2.default.error(err);
});
});
}).then(null, function (err) {
var statusCode = '500';
if (err && err.message.indexOf('ENOTFOUND') > -1) {
statusCode = '504';
}
// 出错也要处理下
return triggerBeforeRes.call(com, (0, _merge2.default)({ statusCode: statusCode }, resInfo, { bodyDataErr: err, headers: {} })).then(function () {
return _promise2.default.reject(err);
});
});
};
var remote = function remote(reqInfo, resInfo) {
var req = reqInfo.req;
var res = resInfo.res;
var com = this;
var isSecure = req.connection.encrypted || req.connection.pai;
var oldProtocol = !!isSecure ? 'https' : 'http';
return _promise2.default.resolve().then(function () {
var t = /^\/.*/;
var hostname = reqInfo.host.split(':')[0];
if (!_net2.default.isIP(hostname)) {
reqInfo.headers.host = reqInfo.host;
}
// 请求选项
var options = {
hostname: hostname,
port: reqInfo.port || (reqInfo.protocol === 'http' ? 80 : 443),
path: t.test(reqInfo.path) ? reqInfo.path : '/' + reqInfo.path,
method: reqInfo.method,
headers: reqInfo.headers
};
if (reqInfo.protocol === 'https') {
options.rejectUnauthorized = false;
// 旧的协议是http-即http跳转向https--从新生成证书
if (oldProtocol === 'http') {
var _getCert = (0, _cert.getCert)(hostname),
key = _getCert.privateKey,
cert = _getCert.cert;
options.key = key;
options.cert = cert;
}
}
return options;
}).then(function (options) {
return detailHost.call(com, options, reqInfo, resInfo);
}).then(function (options) {
return proxyReq.call(com, options, reqInfo, resInfo, req);
});
};