catproxy
Version:
a node proxy or host change tools
493 lines (437 loc) • 13.9 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = function (reqInfo, resInfo) {
var self = this;
var res = resInfo.res;
var req = reqInfo.req;
// 当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
}
});
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 && result.res) {
reqInfo = result;
}
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
}
});
return { reqInfo: reqInfo, resInfo: resInfo };
}).then(function (_ref4) {
var reqInfo = _ref4.reqInfo;
var resInfo = _ref4.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) {
_log2.default.error('proxy request err: ' + err);
(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) {
var info = (0, _merge2.default)({}, resInfo);
delete info.res;
return _evt.beforeRes.call(this, info).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;
var _resInfo$headers = resInfo.headers;
var headers = _resInfo$headers === undefined ? {} : _resInfo$headers;
var statusCode = resInfo.statusCode;
var res = resInfo.res;
headers['loacl-file'] = _querystring2.default.escape(fileAbsPath);
delete headers['content-length'];
delete headers['content-encoding'];
if (!headers['content-type']) {
var mimeType = _mime2.default.lookup((_path2.default.extname(fileAbsPath) || "").slice(1));
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;
var headers = _resInfo$headers2 === undefined ? {} : _resInfo$headers2;
var res = resInfo.res;
delete headers['content-encoding'];
delete headers['content-length'];
return _promise2.default.reject(err);
});
};
// 处理将 域名转换成ip
var detailHost = function detailHost(result, reqInfo, resInfo) {
// 取当前启动的port
var com = this;
var _config$get = config.get();
var port = _config$get.port;
var 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);
})) {
return _promise2.default.reject('Dead circulation');
}
return (0, _merge2.default)(result, {
hostname: address
});
}, function (err) {
var res = resInfo.res;
return triggerBeforeRes.call(com, (0, _merge2.default)({}, resInfo, { bodyDataErr: err, headers: {} })).then(function (_ref) {
var statusCode = _ref.statusCode;
var headers = _ref.headers;
delete headers['content-encoding'];
delete headers['content-length'];
return _promise2.default.reject(err);
});
});
};
// 真正代理请求
var proxyReq = function proxyReq(options, reqInfo, resInfo, req) {
var com = this;
return new _promise2.default(function (resolve, reject) {
// 发出请求
_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();
req.pipe(proxyReq);
}
} else {
// 没有数据就直接end否则读取数据
proxyReq.end();
}
// 出错直接结束请求
proxyReq.on("error", function (err) {
reject(err);
});
}).then(function (_ref2) {
var proxyRes = _ref2.proxyRes;
var remoteUrl = _ref2.remoteUrl;
var reqInfo = _ref2.reqInfo;
var resInfo = _ref2.resInfo;
var res = resInfo.res;
// 数据太大的时候触发
var err = {
message: 'request entity too large',
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;
// log.debug('in size', LIMIT_SIZE, l);
if (!isFired) {
isFired = true;
var statusCode = resInfo.statusCode;
var headers = resInfo.headers;
delete headers['content-length'];
headers['remote-url'] = _querystring2.default.escape(remoteUrl);
res.writeHead(statusCode || 200, headers);
res.write(_buffer.Buffer.concat(resBodyData));
res.write(chunk);
resBodyData = [];
} 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;
var headers = resInfo.headers;
var 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 {
return resInfo;
}
}).then(function (_ref3) {
var headers = _ref3.headers;
var bodyData = _ref3.bodyData;
// 转换head大小写问题
if (!res.headers) {
res.headers = headers;
}
res.end();
res.emit('resBodyDataReady', isError ? err : null, bodyData || []);
}, function (err) {
_log2.default.error(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);
var key = _getCert.privateKey;
var 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);
});
};