最近有個需求,須要對業務管理後臺的操做記錄進行上報。通常這種上報需求都是又後臺同窗來作比較合適的。可是由於後臺人力的緣由。這個工做落到了我這個小前端的頭上。這裏記錄下作這個需求踩的一些坑。前端
作爲一個前端工程師,寫代理腳本第一選擇確定是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。
此文已由做者受權騰訊雲技術社區發佈,轉載請註明文章出處