UNPKG

gcl

Version:

码农村nodejs类库,完成解决回调陷阱,配置框架,IOC框架,统一多DB访问框架,可扩展日志框架和io/db/net/thread/pool 克隆表达式,加解密算法等等一系列基础类库和算法的实现

487 lines (482 loc) 14.3 kB
import V from "../common/tool"; import H from "http"; import HS from "https"; import U from "url"; import Z from "zlib"; import F from "fs"; import P from "path"; import { ArrayStream } from "../collection/arraystream"; import C from "./cookie"; import I from "../io/tool"; import { stringify } from "querystring"; import { decode } from "iconv-lite"; /** * 处理字符集不标准问题 * @param {*} buffer * @param {*} encoding */ const convert = (buffer = new Buffer(), coding = "utf-8") => !coding.eq("utf-8") && !coding.eq("utf8") ? decode(buffer, coding) : buffer.toString(); /** * request全Tool对象的基本方法可以输入 options=url.parse,stream,func(err,resp,code,cencoding,encoding); 返回req 需要手动完成write与end操作 可以针对GZIP等方式自动解压还原文件内容 */ export const request = (options, stream, func) => { options = V.merge( { method: "GET", headers: { Accept: "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8", "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.11 Safari/537.36", "Accept-Encoding": "gzip, deflate", }, }, options ); const HA = options.protocol.toLowerCase() == "https:" ? HS : H; return HA.request(options, (resp) => { var contentencoding = (resp.headers["content-type"] && resp.headers["content-type"].split("=")[1]) || "UTF-8"; var encoding = resp.headers["content-encoding"] || ""; resp.on("error", (err) => { console.log(err); if (func) func.apply(null, [err]); }); stream.on("finish", function () { if (resp.statusCode == 200) { if (func) func.apply(null, [ null, resp, resp.statusCode, contentencoding, encoding, ]); } else { //V.showException(new Error(resp.statusCode + '状态不等于200')); if (func) func.apply(null, [ new Error( resp.statusCode + "状态不等于200:" + (stream.toArray ? convert( Buffer.from(stream.toArray()), contentencoding || encoding ) : "") ), ]); } }); switch (encoding.toLowerCase()) { case "gzip": resp.pipe(Z.createGunzip()).pipe(stream); break; case "deflate": resp.pipe(Z.createInflate()).pipe(stream); break; default: resp.pipe(stream); break; } }); }; export const WebClient = class { constructor() { const { _, __ } = pri(this); _.cookies = {}; _.timeout = 60000; } get(url, data = "", headers = {}, method = {}, original = false) { const { _, __ } = pri(this); data = typeof data == "string" ? data : stringify(data); return V.callback2((call) => { const stream = new ArrayStream(); url = data ? `${url}${url.indexOf("?") >= 0 ? "&" : "?"}${("" + data).trim("&")}` : url; const req = request( V.merge( { headers: { Cookie: C.toString(_.cookies, url) }, }, U.parse(url), { headers: headers }, method ), stream, (err, resp, code, cencoding, encoding) => { if (err) call(err); else { C.merge(_.cookies, C.parse(resp.headers["set-cookie"])); call( null, original ? Buffer.from(stream.toArray()) : convert(Buffer.from(stream.toArray()), cencoding || encoding) ); } } ); req.on("error", function (e) { call(e); }); req.setTimeout(_.timeout); req.end(); }); } post(url, data = "", headers = {}, method = {}) { const { _, __ } = pri(this); //兼容JSON格式输入 data = typeof data == "string" ? data : stringify(data); return V.callback2((call) => { const stream = new ArrayStream(); const req = request( V.merge( { method: "POST", headers: { "Content-Type": "application/x-www-form-urlencoded", "Content-Length": Buffer.byteLength(data), Cookie: C.toString(_.cookies, url), }, }, U.parse(url), { headers: headers }, method ), stream, (err, resp, code, cencoding, encoding) => { if (err) call(err); else { C.merge(_.cookies, C.parse(resp.headers["set-cookie"])); call( null, convert(Buffer.from(stream.toArray()), cencoding || encoding) ); } } ); req.on("error", function (e) { call(e); }); req.write(data); req.setTimeout(_.timeout); req.end(); }); } getJson(url, data = "", headers = {}, method = {}) { const { _, __ } = pri(this); data = typeof data == "string" ? data : stringify(data); return V.callback2((call) => { const stream = new ArrayStream(); url = data ? `${url}${url.indexOf("?") >= 0 ? "&" : "?"}${("" + data).trim("&")}` : url; const req = request( V.merge( { method: "GET", headers: { "Content-Type": "application/x-www-form-urlencoded", "Content-Length": Buffer.byteLength(data), Cookie: C.toString(_.cookies, url), }, }, U.parse(url), { headers: headers }, method ), stream, (err, resp, code, cencoding, encoding) => { if (err) call(err); else { C.merge(_.cookies, C.parse(resp.headers["set-cookie"])); call( null, convert(Buffer.from(stream.toArray()), cencoding || encoding) ); } } ); req.on("error", function (e) { call(e); }); // req.write(V.toJsonString(data)); req.setTimeout(_.timeout); req.end(); }); } /** * post方法实现保留cookie的会话上传文件操作url,path(;分隔的字符串或者文件名数组),func(err,data) * 鸣谢http://www.soso.io/article/48643.html */ postJson(url, data = {}, headers = {}, method = {}) { const { _, __ } = pri(this); return _.post( url, V.toJsonString(data), V.merge( { "Content-Type": "application/json", }, headers ), method ); } /** * post方法实现保留cookie的会话上传文件操作url,path(;分隔的字符串或者文件名数组),func(err,data) * 鸣谢http://www.soso.io/article/48643.html */ async upload(url, path, headers = {}, method = {}) { const { _, __ } = pri(this); let paths = V.isArray(path) ? path : path.split(";").filter((v) => V.isValid(v)); let err = V.sb(); let ret = []; let boundaryKey = Math.random().toString(16); let enddata = `\r\n----${boundaryKey}--`; //定义尾部 var i = 0; var contentlength = 0; await V.each( paths, async (v) => { const pjson = P.parse(P.resolve(P.normalize(v))); v = P.format(pjson); let isTrue = await V.callback2((call2) => F.exists(v, (ist) => call2(null, ist)) ); if (!isTrue) { err.append(v + "目标文件未找到"); return false; } try { let stat = await V.callback2(F.stat, F, v); var content = Buffer.from( "\r\n----" + boundaryKey + "\r\n" + "Content-Type: application/octet-stream\r\n" + 'Content-Disposition: form-data; name="' + "file" + i++ + '"; filename="' + pjson.base + '"\r\n' + "Content-Transfer-Encoding: binary\r\n\r\n", "utf-8" ); ret.push({ content: content, path: v }); contentlength += content.length + stat.size; } catch (e) { err.append(v + "目标文件stat获取出现问题:" + e.message); } return false; }, true ); return V.callback2((call) => { const stream = new ArrayStream(); const req = request( V.merge( { method: "POST", headers: { "Content-Type": "multipart/form-data; boundary=--" + boundaryKey, "Content-Length": contentlength + Buffer.byteLength(enddata), Cookie: C.toString(_.cookies, url), }, }, U.parse(url), { headers: headers }, method ), stream, (err2, resp, code, cencoding, encoding) => { if (err2) call(err.clear() + "\r\n" + err2.stack); else { C.merge(_.cookies, C.parse(resp.headers["set-cookie"])); call( null, convert(Buffer.from(stream.toArray()), cencoding || encoding) ); } } ); req.on("error", function (e) { call(e); }); req.setTimeout(_.timeout); V.each( ret, (v, call2) => { var file = F.createReadStream(v.path, { bufferSize: 4 * 1024 }); //写入头部 req.write(v.content); file.on("end", call2); //写入文件 file.pipe(req, { end: false }); }, true ) .then(() => req.end(enddata)) .catch((e) => console.log(e.stack)); }); } /** * get方法实现保留cookie的会话下载文件操作url,path,func(err,data) */ async download(url, path, headers = {}, method = {}) { const { _, __ } = pri(this); await I.createDir(path); let file = F.createWriteStream(path); let opt = U.parse(url); opt.headers = V.merge({ Cookie: C.toString(_.cookies, url) }, headers); V.merge(opt, method, true); return V.callback2((call) => { let req = request(opt, file, (err, resp, code, cencoding, encoding) => { if (err) call(err); else { C.merge(_.cookies, C.parse(resp.headers["set-cookie"])); call(null, true); } }); req.on("error", function (e) { call(e); }); req.setTimeout(_.timeout); req.end(); }); } }; /** * 新建WebClient类对象返回get方法的对象url,func(err,data) */ export const get = (url, data, headers, method, original) => new WebClient().get(url, data, headers, method, original); /** * post(url,func):新建WebClient类对象返回post方法的对象url,string || Buffer,func(err,data) */ export const post = (url, data, headers, method) => new WebClient().post(url, data, headers, method); /** * 新建WebClient类对象返回post方法的对象url,string || JSON,func(err,data) */ export const postJson = (url, data, headers, method) => new WebClient().postJson(url, data, headers, method); /** * 新建WebClient类对象返回post方法的对象url,string || JSON,func(err,data) */ export const getJson = (url, data, headers, method) => new WebClient().getJson(url, data, headers, method); /** * 新建WebClient类对象返回post方法的文件对象url,path,func(err,data) */ export const upload = (url, path, headers, method) => new WebClient().upload(url, path, headers, method); /** * 新建WebClient类对象返回get方法的文件对象url,path,func(err,data) */ export const download = (url, path, headers, method) => new WebClient().download(url, path, headers, method); /** * createReverseProxy(port,[address]):非常简单的TCP代理服务器 */ export const createReverseProxy = function (port, address) { if (address) { } else throw new Error( "Need address Array(e.g [{host:127.0.0.1,port:1001},{host:127.0.0.1,port:1002}]) as ports" ); address = V.isArray(address) ? address : [address]; var w = 0; var proxy = (client, c) => { client.pipe(c); c.pipe(client); }; var find = () => { var start = w; w = (w + 1) % address.length; while (start != w) { var p = address[w]; if (p.err) { if (p.err.passtime.sub("s", new Date()) < 0) { delete p.err; return p; } } else return p; w = (w + 1) % address.length; } return address[start]; }; var tcpServer = net .createServer((c) => { var p = find(); try { var client = net.createConnection(p.port, p.host, () => proxy(client, c) ); } catch (e) { console.log(e.stack); p.err = { e: e, passtime: new Date().add("s", 5) }; c.end(new Buffer(e.message, "utf-8")); } }) .listen(port, function () { console.log("Proxy Server listen " + port + " Now!"); }); tcpServer.on("error", function (err) { output("server error ,check the port..." + err); }); return tcpServer; }; /** * createReverseProxy(proxy,host,proxyports):非常简单的TCP代理服务器 */ export const createReverseProxy2 = function (port, host, proxyports) { if (proxyports) { } else throw new Error("Need ProxyPorts Array(e.g [1001,1002,1003]) as ports"); proxyports = V.isArray(proxyports) ? proxyports : [proxyports]; var w = 0; var proxy = (client, c) => { client.pipe(c); c.pipe(client); }; var tcpServer = net .createServer((c) => { w = (w + 1) % proxyports.length; var p = proxyports[w]; var client = host ? net.createConnection(p, host, () => proxy(client, c)) : net.createConnection(p, () => proxy(client, c)); }) .listen(port, function () { console.log("Proxy Server listen " + port + " Now!"); }); tcpServer.on("error", function (err) { output("server error ,check the port..." + err); }); return tcpServer; }; export default { request, WebClient, get, getJson, post, postJson, upload, download, createReverseProxy, createReverseProxy2, }; const pri = V.pris();