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*include\s+file=(["']).+?\1\s*-->/g);        console.log('_ssiReadFile2', match);        if (match) {            match.forEach((m) => {                var fileStr = m.match(/<!--#\s*include\s+file=(["'])(.+?)\1\s*-->/)[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*include\s+file=(["'])(.+?)\1\s*-->/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;    }};