最近有个需求,须要对业务管理后台的操做记录进行上报。通常这种上报需求都是又后台同窗来作比较合适的。可是由于后台人力的缘由。这个工做落到了我这个小前端的头上。这里记录下作这个需求踩的一些坑。前端
作为一个前端工程师,写代理脚本第一选择确定是node。不过在此以前,要把请求代理到机器A上面的node服务上面。这里使用了tnginx。在nginx.config文件里面添加如下配置并重启。把cgi域名下的请求,代理到机器上面的8000端口node 服务。node
server{ listen 80; server_name cgi.qqcomic.oa.com admin.cgi.qqcomic.oa.com; access_log /usr/local/services/tnginx_1_0_0-1.0/access.log; location / { proxy_pass http://127.0.0.1:8000; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $http_host; } }
而后使用node的http-proxy模块,起一个代理server,就像这样。nginx
var httpProxy = require('http-proxy'); var http = require('http') http.createServer(function(req, res) { proxy.web(req, res, { target: http://10.213.167.135}); }).listen(8000);
本机使用fiddler 代理cgi域名到测试机器A的ip,刷新一下,成功访问到cgi内容。(ps: 注意idc机器是没有dns解析服务的,这里须要在 /etc/hosts文件上面添加相关域名的ip地址)web
成功实现请求代理是一个好的开始。如今,须要开始搞点事情了。首先,咱们须要获取请求的参数,这些参数多是在url里面,也多是在POST实体里面。url里面的参数很容易拿到,只须要读取req对象的url就能获取。POST实体里面的数据获取比较麻烦,由于POST请求的种类比较多,手动解析比较麻烦。这里使用了formidable模块来解析。而后把解析完成的结果挂载在req对象上面,方便后面获取。前端工程师
function getBody(request){ var formidable = require('formidable'); var form = new formidable.IncomingForm(),fields = {}; //..巴拉巴拉,解析出参数,挂载在request对象上面 }
除了请求的参数,咱们还须要获取cgi回包的数据,这样才能判断这个请求是否是有效的。获取回包数据,能够在res对象上面监听data事件,拼接回包数据。相似这样封装一个方法:函数
function getResRawData(res,callback){ var resData = '' res.on('data', function(chunk){ resData = resData + chunk.toString(); }); res.on('end', function(chunk){ try { resData = JSON.parse(resData); callback(null,resData) }catch (e){ callback(e) } }); res.on('error', function(err){ callback(err) }); }
比较坑一点的是,回包可能会被gzip压缩,这样咱们上面代码获得的会是乱码。所以处理回包的时候,要判断回包的content-encoding是否是gzip,若是是gzip的话,须要使用node的zlib模块进行解压。post
获取了请求的参数和回包内容,咱们就能够进行数据上报了,上报的时机应该是在代理请求回包以后。http-proxy模块提供了proxyRes事件给咱们监听,咱们能够在这个事件的回调函数里面,获取回包的内容,并调用上报方法,使用node的request模块进行数据上报。相似这样:测试
var request = require('request'); proxy.on('proxyRes', function (proxyRes,req,res) { //获取回包内容 getResRawData(proxyRes,function(err,data){ //发起请求上报 request.post(data, function(err,httpResponse,body){ console.log(body) }) }) });
系统的cgi可能不仅是一个命令,可能不仅是一种回包格式。因此咱们须要添加一个路由模块,把不一样请求,映射到对应的处理器上面。能够比较简单的根据正则匹配url,返回不一样的模块字符串,而后在代理请求回包后,根据模块字符串require这些模块去处理对应的请求。相似这样:ui
http.createServer(function(req, res) { var route = router(req);//根据请求url,返回对应的模块字符串 //根据请求,获取处理请求的模块 var target = (route && route.target) || null; if(!target){ res.end('bad request') }else{ //注入配置到req对象里面,后面会用到 req.routerConfig = route proxy.web(req, res, { target: target}); } }).listen(8000); proxy.on('proxyRes', function (proxyRes,req,res) { //获取回包内容 getResRawData(proxyRes,function(err,data){ //根据路由配置,加载对应的处理器去处理请求 if(req.routerConfig && req.routerConfig.handle){ action = require(req.routerConfig.handle); action.handle(req,data) } }) });
附:系统设计流程图url
有了node以后,前端有了更大的舞台,能够帮助解决一些后台的工做。此次的需求只是一个小小的应该例子,后续咱们还能够在这个proxy server的基础上,添加白名单作权限限制,限制某些rtx用户只能操做固定的cgi。
此文已由做者受权腾讯云技术社区发布,转载请注明文章出处