app.js
var http = require('http');
http.createServer(function (req, res) {
require("./handle.js").sayHello();
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end('Hello World\n');
}).listen(1337, '127.0.0.1');
console.log('Server running at http://127.0.0.1:1337/');
handle.js
module.exports.sayHello=function(){
console.log(" HEEEEEEloo");
;
node app 启动以后,访问 http://127.0.0.1:1337/ 控制台有输出 如果修改handle.js 以后,必须要重启动node app require 只有第一次加载的时候会读文件 nodejs应该是动态脚本,能不能做到象php那样,require的脚本修改了代码能自动生效 ?
开发时使用supervisor
nodemon / supervisor 都可以。。。
$ npm i nodemon supervisor -g
读者是不是想问的是用这个来实现代码热部署呢,哈哈,其实是可以的哟,代码结构整理好,controller层 dao层的代码改动都可以热部署哦,不代表整个nodejs工程里的所有文件都可以更改并支持热部署啦【有些对象还是要经过的处理滴】,不过我相信大多数同学其实修改的是controller层 dao层的代码或者说配置文件啦,写个配置文件,所有的需要热部署的文件都注册在里面,然后写个http接口,该接口,干嘛用的呢,当然就是delete require[“module_name”]用的啦
客户端代码【触发服务器端删除行为用的啦】: var ip=“your_server_ip”; var name=process.env.DEL_MODULE || “all”;//你想删除的模块名称 var params = querystring.stringify({moduleName:name}); console.log(params); var options = {host: ip,port: 2000,path: ‘/delModuleCache’,method: ‘post’, headers: {‘Content-Type’: ‘application/x-www-form-urlencoded’, ‘Content-Length’: params.length} }; var req = http.request(options, function(res) { console.log('STATUS: ’ + res.statusCode); console.log('HEADERS: ’ + JSON.stringify(res.headers)); res.setEncoding(‘utf8’);//设置字符编码 var _data="";//返回数据流 res.on(‘data’, function (chunk) {//数据 _data+=chunk; }); // 结束回调 res.on(‘end’, function(){ console.log(“receive:”,_data) }); req.on(‘error’, function(e) { console.log('problem with request: ’ + e.message); }); }); req.write(params); req.end();
服务器端代码【稍稍复杂一点】: 实现delModuleCache逻辑是首先的啦,这是我目前的实现,因为涉及到通知cluster模块其他worker进程也删除,所以稍复杂: //删除注册在fn.js里的各个模块的缓存 exports.delModuleCache=function(req, res){//具体逻辑实现 var startUpLog=logFactory.getlogger(“startUpLog”); startUpLog.info(“start to delete module cache”); //body may like:{moduleName:***} var body=req.body; if(body.moduleName){ var moduleName=body.moduleName; var fn=require("./fn"); if(moduleName.indexOf(",")!=-1){//表示删除多个模块缓存 var names=moduleName.split(","); for(var idx in names){ if(!fn.fnPool[names[idx]]){ return res.send(“module:”+names[idx]+" not exist,please check file:fn.js"); } } startUpLog.info(“receive from post:”+process.pid+" and delete cache"); process.send({broadcastAll: {moduleName: names}});//通知其他node进程,也删除缓存 //res.send(fn.del(names)); res.send(“delete cache “+moduleName+” successfully”); }else if(moduleName==“all”){ startUpLog.info(“receive from post:”+process.pid+" and delete cache"); process.send({broadcastAll: {moduleName: moduleName}});//通知其他node进程,也删除缓存 //res.send(fn.del(moduleName)); res.send(“delete cache “+JSON.stringify(fn.fnPool)+” successfully”); }else{ if(fn.fnPool[moduleName]){ startUpLog.info(“receive from post:”+process.pid+" and delete cache"); process.send({broadcastAll: {moduleName: moduleName}});//通知其他node进程,也删除缓存 //res.send(fn.del(moduleName)); res.send(“delete cache “+moduleName+” successfully”); }else{ res.send(“input param incorrect,moduleName:”+moduleName+" not register in fn.file"); } } }else{ res.send(“input param incorrect,a correct example should be:{moduleName:‘gogogo’}”); } };
程序入口文件app.js里:【涉及到保密的地方,代码都被删掉了,重要的地方展示出来,你懂了就ok了,你懂滴】 var cluster = require(‘cluster’); var logFactory=require(’./app/logFramework/logFactory’); var startUpLog=logFactory.getlogger(“startUpLog”);
if (cluster.isMaster) { console.log(’[master] ’ + “start master…”); var cpuCount = require(‘os’).cpus().length; for (var i = 0; i < cpuCount; i += 1) { var worker_process=cluster.fork(); //主进程里监听来自各个工作进程的消息 worker_process.on(‘message’, function(msg) { var cur_id=worker_process.id; startUpLog.info(“worker:” + cur_id+"'s handle in master receive msg:"+JSON.stringify(msg)+"!"); if(msg.broadcastAll){ var to_send=msg.broadcastAll; startUpLog.info(“worker:” + cur_id+"'s handle in master start to broadcast msg:"+JSON.stringify(to_send)+" to other workers"); sendToAllWorker(to_send); } }); }
//master向各个worker发消息
function sendToAllWorker(to_send,exclude_id){
var workers=cluster.workers;
for (var idx in workers) {
var cur_worker=workers[idx];
if(exclude_id){
if(cur_worker.id!=exclude_id){
startUpLog.info("master[worker:"+exclude_id+"] start to send msg:"+JSON.stringify(to_send)+" to "+"worker:" + cur_worker.id);
cur_worker.send(to_send);
}
}else{
startUpLog.info("master start to send msg:"+JSON.stringify(to_send)+" to "+"worker:" + cur_worker.id);
cur_worker.send(to_send);
}
}
}
cluster.on('listening', function (worker, address) {
startUpLog.info('[master] ' + 'listening: worker' + worker.id + ',pid:' + worker.process.pid + ', Address:' + address.address + ":" + address.port);
});
cluster.on('disconnect', function (worker) {
startUpLog.info('[master] ' + 'disconnect: worker' + worker.id);
});
// Listen for dying workers
cluster.on('exit', function (worker) {
// Replace the dead worker, we're not sentimental
console.log('Worker ' + worker.id + ' died :(');
cluster.fork();
});
} else if(cluster.isWorker) { var cur_worker=cluster.worker; //工作进程监听来自主进程的消息 cur_worker.on(‘message’, function (msg) { var cur_id = cur_worker.id; startUpLog.info(“worker:” + cur_id + " receive msg from master:" + JSON.stringify(msg) + “!”); if (msg.moduleName) { startUpLog.info(“worker:” + cur_id + " start to delete cache of " + JSON.stringify(msg) + “!”); var moduleName = msg.moduleName; var fn = require("./routes/fn"); if (Array.isArray(moduleName)) {//表示删除多个模块缓存 fn.del(moduleName); } else if (moduleName == “all”) { fn.del(moduleName); } else { if (fn.fnPool[moduleName]) { startUpLog.info(“watch worker id:” + cur_worker.id); fn.del(moduleName); } } } else if (msg.broadcastAll) { var to_send = msg.broadcastAll; startUpLog.info(“worker:” + cur_id + " start to broadcast msg:" + JSON.stringify(to_send) + " to other workers"); sendToAllWorker(to_send, cur_id); } });
console.log('[worker] ' + "start worker ..." + cur_worker.id);
var express = require('express'), http = require('http'), path = require('path');
var app = express();
var mysql = require('./app/dbFramework/lib/mysqlFactory');
var redis = require("./app/dbFramework/lib/redisFactory");
app.configure(function(){
app.set('port', process.env.PORT || 2000);
app.use(express.compress());//开启 gzip 压缩功能
app.use(express.favicon());
app.use(express.logger('dev'));
app.use(express.bodyParser());
app.use(express.methodOverride());
});
app.configure('development', function(){
app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
});
app.configure('production', function(){
app.use(express.errorHandler());
});
var urlrouter = require('urlrouter');
var router = urlrouter(function (app) {
var dataHandle = require('./routes/dataHandle');
app.post('/delModuleCache',dataHandle.delModuleCache);
//把通配符放于最后处理。这样没有经过路由的所有页面默认由日志记录:【因协议未定义而无法连接】_404Error
app.post('*', function(req, res){
console.log("************ test test 404 not found!,input URL:"+req.originalUrl);
var _404Error=require('./app/logFramework/logFactory').getlogger("404Error");
_404Error.error("404 not found! input URL:"+req.originalUrl);
_404Error.error("data:"+JSON.stringify(req.body.data)+"\n");
});
});
app.use(router);
process.on('uncaughtException', function(err) {
var logFactory=require('./app/logFramework/logFactory');
var exceptionLog=logFactory.getlogger("exceptionLog");
exceptionLog.error(' Caught exception: ' + err.stack);
console.error(' Caught exception: ' + err.stack);
});
http.createServer(app).listen(app.get('port'), function(){
startUpLog.info("midas-master listening on port " + app.get('port'));
});
}
//最最重要的来啦!fn.js是这个样子滴 var daoDir = “…/app/dao/”; var actionDir = “…/app/controller/”; var dataDir = “…/app/data/”;
var me = {}; var fnPool = { userDao: daoDir + “userDao”, deleteItem: actionDir + “deleteItem”, buildings: dataDir + “buildings”
};
me.fnPool=fnPool;
me.del=function(name){ var info=""; if(Array.isArray(name)){ for(var idx in name){ var curInfo=“delete module cache:”+name[idx]; info+=(curInfo+"\n"); console.log(curInfo); delete require.cache[require.resolve(fnPool[name[idx]])]; } }else if(name==“all”){ for(var name in fnPool){ var curInfo=“delete module cache:”+name; info+=(curInfo+"\n"); console.log(curInfo); delete require.cache[require.resolve(fnPool[name])]; } }else{ info=“delete module cache:”+name; console.log(info); delete require.cache[require.resolve(fnPool[name])]; } return info; }; module.exports=me;
呜呜,其实我发现说了这么多,最关键的一句话,就是:delete require.cache[require.resolve(“your_module_name”)];