在项目中,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(/ /g); console.log('_ssiReadFile2', match); if (match) { match.forEach((m) => { var fileStr = m.match(/ /)[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(/ /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; }};