搞點事情,使用node搭建反向代理

導語

最近有個需求,須要對業務管理後臺的操做記錄進行上報。通常這種上報需求都是又後臺同窗來作比較合適的。可是由於後臺人力的緣由。這個工做落到了我這個小前端的頭上。這裏記錄下作這個需求踩的一些坑。前端

1、實現反向代理

作爲一個前端工程師,寫代理腳本第一選擇確定是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

2、獲取請求的相關數據

成功實現請求代理是一個好的開始。如今,須要開始搞點事情了。首先,咱們須要獲取請求的參數,這些參數多是在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

3、進行數據上報

獲取了請求的參數和回包內容,咱們就能夠進行數據上報了,上報的時機應該是在代理請求回包以後。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)
               })
        })
    });

4、劃分路由模塊

系統的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

5、小結

有了node以後,前端有了更大的舞臺,能夠幫助解決一些後臺的工做。此次的需求只是一個小小的應該例子,後續咱們還能夠在這個proxy server的基礎上,添加白名單作權限限制,限制某些rtx用戶只能操做固定的cgi。

此文已由做者受權騰訊雲技術社區發佈,轉載請註明文章出處

相關文章
相關標籤/搜索