node anyproxy ssi简易支持

在项目中,ssi include是一个比较常用的功能,这样我们就可以通过web服务器的支持,将公用的html提取出来,改一个文件就会修改全部内容

但是这也带来了问题,在开发的时候没办法的刷新查看,需要提交测试服务器才可以,当然也可以通过在本地通过nginx服务器做到这些。

现在我们有了nodejs,github上面也有很多好的本地代理项目,anyproxy,whistle,livepool...

平时主要用 whistle 操作配置上面都很简单,通过简单配置也可以实现很多功能

livepool,装了下,看着想fiddler,操作起来主要感觉主要是界面操作,就没怎么用

anyproxy,这个是需要自己写js,定义规则的,灵活性好些,但是写代码总归麻烦的

今天通过对比,感觉anyproxy实现node ssi功能比较简单些,其实也很简单,详见代码 时间有限,都是通过同步api写的,略有遗憾

/*
  read the following wiki before using rule file
  https://github.com/alibaba/anyproxy/wiki/What-is-rule-file-and-how-to-write-one
*/
"use strict";
const fs = require('fs');
const url = require("url");
const path = require("path");
var _getNewFPath = function (newUrl) {
    var urlObject = url.parse(newUrl, true);
    return path.join(this.hostFilePath, urlObject.pathname);
}
const config = [
    {
        urlInclude: 'http://mall.snail.com/pickCard/',
        hostFilePath: 'D:/snailshop/mall-snail-com/mall',
        ssi: true,
        getNewFPath: function (newUrl) {
            var urlObject = url.parse(newUrl, true);
            if (newUrl.indexOf('http://mall.snail.com/includes/') != -1) {
                return path.join('D:/snailshop/mall-snail-com/', urlObject.pathname);
            }
            return path.join(this.hostFilePath, urlObject.pathname);
        }
    },
    {
        urlInclude: 'http://static.snail.com/',
        hostFilePath: 'D:/snailshop/mall-snail-com/public',
        getNewFPath: _getNewFPath
    }
];

var map = {};
var ssiReadFile = function (reqUrl, ssiOpt) {
    map = {};
    return _ssiReadFile(reqUrl, ssiOpt, [])
};
var _ssiReadFile = function (reqUrl, ssiOpt, accessPath) {
    var readFPath = ssiOpt.getNewFPath(reqUrl);
    console.log('_ssiReadFile1', readFPath)
    var stat = fs.statSync(readFPath);
    var content;
    if (stat && stat.isFile()) {
        content = fs.readFileSync(readFPath, {encoding: 'utf8'});
        var match = content.match(/<!--#s*includes+file=(["']).+?1s*-->/g);
        console.log('_ssiReadFile2', match);
        if (match) {
            match.forEach((m) => {
                var fileStr = m.match(/<!--#s*includes+file=(["'])(.+?)1s*-->/)[2];
                var newUrl = url.resolve(reqUrl, fileStr);
                if (accessPath.indexOf(newUrl) != -1) {//存在循环
                    map[newUrl] = "loop " + newUrl +' in [ '+ accessPath.join() + ']';
                } else if (!map[newUrl]) {
                    var _access = accessPath.slice(0);
                    _access.push(newUrl);
                    map[newUrl] = _ssiReadFile(newUrl, ssiOpt, _access);
                }
            })
            content = content.replace(/<!--#s*includes+file=(["'])(.+?)1s*-->/g, function (a, b, fileStr) {
                var newUrl = url.resolve(reqUrl, fileStr);
                return map[newUrl];
            });
        }
    } else {
        content = 'not find file ' + readFPath;
    }
    return content;
}

module.exports = {
    summary: function(){
        return "mall 项目";
    },
    replaceRequestOption : function(req, option){
        var host = option.headers.host;
        if(host == "mall.snail.com" || host == "static.snail.com" || host == "m.mall.snail.com"){
            option.hostname = "10.13.0.206";
            option.port = "80";
        } else if (host == "mobile.snail.com" || host == "m.mobile.snail.com"){
            option.hostname = "10.13.0.205";
            option.port = "80";
        }  else if (host == "cmsv3.snailsite.com"){
            option.hostname = "10.110.1.3";
            option.port = "80";
        } 
        
        return option;
    },
    shouldInterceptHttpsReq :function(req){
        return false;
    },
    shouldUseLocalResponse : function(req, reqBody){
        var reqUrl = req.url;
        var urlObject = url.parse(reqUrl, true);
        for (var i = 0, len = config.length; i < len ; i++) {
            let opt = config[i];
            if (reqUrl.indexOf(opt.urlInclude) != -1) {
                let newPath = path.join(opt.hostFilePath, urlObject.pathname);
                let stat = fs.statSync(newPath);
                if (stat && stat.isFile()) {
                    console.log('shouldUseLocalResponse', newPath)
                    req.ssi = opt.ssi || false;
                    req.ssiOpt = opt;
                    return true;
                }
            }
        }
        return false;
    },

    dealLocalResponse : function(req, reqBody, callback){
        console.log('dealLocalResponse', req.ssi);
        if (req.ssi) {
            callback(200, {"content-type": "text/html"}, ssiReadFile(req.url, req.ssiOpt));
        } else {
            callback(200, {}, fs.readFileSync(req.ssiOpt.getNewFPath(req.url)));
        }
        delete req.ssiOpt;
        delete req.ssi;
    }
};
原文地址:https://www.cnblogs.com/legu/p/5712317.html