nodejs

npm install (the command) to work behind proxy

config set strict-ssl false
npm config set registry "http://registry.npmjs.org/"
npm --proxy http://proxy_host:port install packagename

下载最新稳定版本 参考joyent installation nodejs开发指南express3源码
---------------------------------
安装依赖库
 Python 版本 2.5 以上
 sudo apt-get install g++ curl libssl-dev apache2-utils   
 sudo apt-get install git-core
---------------------------------
源码编译安装
 tar -zxf node-v0.8.16.tar.gz
 cd node-v0.8.16
 ./configure --prefix=/opt/node
 make
 sudo make install
 #环境变量设置
 export PATH=$PATH:$NODE_HOME/bin:$NODE_HOME/lib/node_modules
 #终端中启用配置
 source /opt/profile
---------------------------------
Binary安装
 cd /opt/node
 tar -zxf node-v0.8.16-linux-x64.tar.gz
 #环境变量设置
 export PATH=$PATH:$NODE_HOME/bin:$NODE_HOME/lib/node_modules
 #终端中启用配置
 source /opt/profile
---------------------------------
安装NPM(最近nodejs已集成npm)
 集成npm安装
  ./configure --prefix=/opt/node/npm
  make
  sudo make install
  #环境变量设置
   export PATH=$PATH:$NPM_HOME/bin
  #终端中启用配置
   source /opt/profile
 独立安装
  curl http://npmjs.org/install.sh | sh
   or
  cd /opt/node/lib/node_modules/npm/scripts
  sh install.sh
---------------------------------
命令行调试:
  node debug *.js
远程调试:
  node --debug[=port] script.js     #脚本会正常执行不会暂停,默认情况下调试端口是 5858
  node --debug-brk[=port] script.js #调试服务器在启动后会立刻暂停执行脚本,等待调试客户端连接
  #在一个终端中
    node --debug-brk debug.js
    debugger listening on port 5858
  #在另一个终端中
    node debug 127.0.0.1:5858
  ---------------------------------
  run 执行脚本,在第一行暂停
  restart 重新执行脚本
  cont, c 继续执行,直到遇到下一个断点
  next, n 单步执行
  step, s 单步执行并进入函数
  out, o 从函数中步出
  setBreakpoint(), sb() 在当前行设置断点
  setBreakpoint(‘f()’), sb(...) 在函数f的第一行设置断点
  setBreakpoint(‘script.js’, 20), sb(...) 在 script.js 的第20行设置断点
  clearBreakpoint, cb(...) 清除所有断点
  backtrace, bt 显示当前的调用栈
  list(5) 显示当前执行到的前后5行代码
  watch(expr) 把表达式 expr 加入监视列表
  unwatch(expr) 把表达式 expr 从监视列表移除
  watchers 显示监视列表中所有的表达式和值
  repl 在当前上下文打开即时求值环境
  kill 终止当前执行的脚本
  scripts 显示当前已加载的所有脚本
  version 显示 V8 的版本
---------------------------------
node-inspector是一个完全基于Node.js的开源在线调试工具
  #node-inspector使用了WebKit Web Inspector,因此只能在Chrome等WebKit内核的浏览器中使用
  命令安装:npm install -g node-inspector
  在终端中通过node --debug-brk=5858 debug.js命令连接你要除错的脚本的调试服务器
  启动 node-inspector:node-inspector
  在浏览器中打开http://127.0.0.1:8080/debug?port=5858,即可显示Web调试工具
---------------------------------
process用于描述当前Node.js进程状态的对象,提供了一个与操作系统的简单接口
 argv.js:
   console.log(process.argv);
 $ node argv.js 2012 name=Eric --v "ningbo"
   [ 'node',
     '/home/work/argv.js',
     '2012',
     'name=Eric',
     '--v',
     'ningbo' ]
 ---------------------------------
 #http://nodejs.org/api/process.html
 process.nextTick(callback)的功能是为事件循环设置一项任务,Node.js会在下次事件循环调响应时调用callback
  compute()和somethingComplicated()是两个较为耗时的函数:
    function doSomething(args, callback) {
     somethingComplicated(args);
     callback();
    }
    doSomething(function onEnd() {
     compute();
    });
   ---------------------------------------
   function doSomething(args, callback) {
    somethingComplicated(args);
    process.nextTick(callback);
   }
   doSomething(function onEnd() {
    compute();
   });
 #不要使用 setTimeout(fn,0)代替 process.nextTick(callback),前者比后者效率要低得多
---------------------------------
 util.inherits(constructor, superConstructor)是一个实现对象间原型继承的函数
---------------------------------
 #http://nodejs.org/api/util.html
 #showHidden-隐藏信息  depth-最大递归的层数,null无限递归  colors-ANSI颜色编码
 util.inspect(object,[showHidden],[depth],[colors])是一个将任意对象转换为字符串的方法,通常用于调试和错误输出
---------------------------------
事件发射器
 events.EventEmitter是事件发射与事件监听器功能的封装
  var events = require('events');
  var emitter = new events.EventEmitter();
  emitter.on('someEvent', function(arg1, arg2) {
    console.log('listener1', arg1, arg2);
  });
  emitter.on('someEvent', function(arg1, arg2) {
    console.log('listener2', arg1, arg2);
  });
  #当error发生时,EventEmitter规定如果没有响应的监听器,Node.js会把它当作异常,退出程序并打印调用栈
  #一般要为发射error事件的对象设置监听器,避免遇到错误后整个程序崩溃
  emitter.on('error', function() {
    console.log('error');
  });
  emitter.emit('someEvent', 'Eric', 2012);
---------------------------------
 文件系统-fs
---------------------------------
 HTTP-http
---------------------------------
控制权转移:
  app.all('/user/:username', function(req, res) {
    res.send('all methods captured');
  });
  app.get('/user/:username', function(req, res) {
    res.send('user: ' + req.params.username);
  });
  #请求总是被前一条路由规则捕获,后面的规则会被忽略
  app.all('/user/:username', function(req, res, next) {
    console.log('all methods captured');
    next();#路由控制权转移给后面的规则
  });
  app.get('/user/:username', function(req, res) {
    res.send('user: ' + req.params.username);
  });
  -----------提高代码的复用程度-----------
  var users = {
    'person': {
     name: 'Eric',
     website: 'http://wen12128.cnblogs.com'
    }
  };
  app.all('/user/:username', function(req, res, next) {
    // 检查用户是否存在
    if (users[req.params.username]) {
      next();
    } else {
      next(new Error(req.params.username + ' does not exist.'));
    }
  });
  app.get('/user/:username', function(req, res) {
    // 用户一定存在,直接展示
    res.send(JSON.stringify(users[req.params.username]));
  });
  app.put('/user/:username', function(req, res) {
    // 修改用户信息
    res.send('Done');
  });
---------------------------------
#更改默认资源库:
  npm config set registry "http://npm.hacknodejs.com/"
 #NPM资源库镜像:{http://registry.npmjs.vitecho.com}-{http://npm.hacknodejs.com/}
  npm --registry "http://npm.hacknodejs.com/" install underscore
---------------------------------
安装supervisor:
 #监视你对代码的改动,并自动重启 Node.js
 npm install -g supervisor
---------------------------------
安装express:
 #-d代表把相依性套件也一起安装
 查看安装包:npm ls
 npm install -gd express
 express --help
 express -t ejs demo
 cd demo && npm install
 REST风格的路由规则:
  GET:[获取app.get(path, callback)]请求获取指定资源。
  HEAD:请求指定资源的响应头。
  POST:[新增app.post(path, callback)]向指定资源提交数据。
  PUT:[更新app.put(path, callback)]请求服务器存储一个资源。
  DELETE:[删除app.delete(path, callback)]请求服务器删除指定资源。
  PATCH:[app.patch(path, callback)]IETF RFC 5789新增的HTTP方法,功能定义是部分更新某个资源
  TRACE:[app.trace(path, callback)]回显服务器收到的请求,主要用于测试或诊断。
  CONNECT:[app.connect(path, callback)]HTTP/1.1 协议中预留给能够将连接改为管道方式的代理服务器。
  OPTIONS:[app.options(path, callback)]返回服务器支持的HTTP请求方法
  所有方法:[app.all(path, callback)]
 #幂等-重复请求多次与一次请求的效果是一样
---------------------------------
启用页面布局功能:
 var partials = require('express-partials')
  app.configure中添加以下内容:
    app.use(partials());
  启用其它布局模板:
    #页面模板时套用admin.ejs作为页面布局
    function(req, res){res.render('userlist',{title: '用户列表后台管理系统',layout: 'admin'});};
---------------------------------
片段视图:
 partials:重复的内容,用于迭代显示,将相对独立的页面块分割出去,而且可以避免显式地使用循环迭代
   app.get('/list',function(req,res){res.render('list',{title:'List',items:[2012,'Eric','express','Node.js']});});
   list.ejs:<ul><%- partial('listitem', items) %></ul>
   listitem.ejs:<li><%= listitem %></li>
---------------------------------
视图助手:
  #express3.0中locals代替dynamicHelpers():
    app.use(function(req,res,next){
      var err = req.flash('error'),success = req.flash('success');
      res.locals.user = req.session.user;
      res.locals.error = err.length ? err : null;
      res.locals.success = success.length ? success : null;
      next();
    });
  允许在视图中访问一个全局的函数或对象,不用每次调用视图解析的时候单独传入
  静态视图助手:任何类型的对象,包括接受任意参数的函数,但访问到的对象必须与用户请求无关,通过app.helpers()函数注册
  动态视图助手:只能是一个函数,该函数不能接受参数,但可以访问req和res对象,通过app.dynamicHelpers()注册
  var util = require('util');
  app.helpers({
   inspect: function(obj) {
    return util.inspect(obj, true);
   }
  });
  app.dynamicHelpers({
   headers: function(req, res) {
    return req.headers;
   }
  });
  app.get('/helper', function(req, res) {
   res.render('helper', {
    title: 'Helpers'
   });
  });
 #视图中调用:
  <%=inspect(headers)%>
---------------------------------
安装MongoDB:
 工程目录中package.json->dependencies中添加一行代码:
  ,"mongodb": "*" #*会默认获取最新版本
 然后运行cd microblog && npm install更新依赖的模块,接下来在工程的目录中创建settings.js文件用于保存数据库的连接信息:
    module.exports = {
      cookieSecret: 'microblog',
      db: 'microblog',
      host: 'localhost',
    };
 在工程目录下新建models目录并创建db.js:
    var settings = require('../settings');
    var Db = require('mongodb').Db;
    var Connection = require('mongodb').Connection;
    var Server = require('mongodb').Server;
    module.exports = new Db(settings.db, new Server(settings.host, Connection.DEFAULT_PORT, {}));
---------------------------------
会话支持:
 工程目录中package.json->dependencies中添加一行代码:
  "connect-mongo": ">= 0.1.7"
 然后运行cd microblog && npm install更新依赖的模块,接下来在app.js中添加:
  var MongoStore = require('connect-mongo');
  var settings = require('./settings');
  app.configure(function(){
    app.set('views', __dirname + '/views');
    app.set('view engine', 'ejs');
    app.use(express.bodyParser());
    app.use(express.methodOverride());
    app.use(express.cookieParser());
    app.use(express.session({
     secret: settings.cookieSecret,
     store: new MongoStore({
      db: settings.db
     })
    }));
    app.use(app.router);
    app.use(express.static(__dirname + '/public'));
  });

---------------------------------
模块的类型:
  Node.js的模块可以分为两大类,一类是核心模块,另一类是文件模块
  核心模块拥有最高的加载优先级,换言之如果有模块与其命名冲突,Node.js总是会加载核心模块
  在不显式指定文件模块扩展名的时候,Node.js会分别试图加上.js(javascript) > .json(json) > .node(c/c++)扩展名
  核心模块:
    Node.js标准API中提供的模块,如fs、http、net、vm等
---------------------------------
按路径加载模块:
  相对路径:require参数以“./”或“../”开头
  绝对路径:require('/home/ms') 将会按照优先级依次尝试加载/home/ms.js、/home/ms.json、/home/ms.node
在node_modules中加载模块:
  如果require参数不以“/”、“./”或“../”开头,而该模块又不是核心模块,那么就要通过查找node_modules加载模块
  如果没有找到,则会在当前目录的上一层中的node_modules目录中继续查找,反复执行这一过程,直到遇到根目录为止
    require('ms.js'):/home/work/node_modules/ms.js > /home/node_modules/ms.js > /node_modules/ms.js
---------------------------------
加载缓存:
  Node.js模块不会被重复加载,这是因为Node.js是通过实际文件名缓存所有加载过的文件模块,而不是通过require()提供的参数缓存的
---------------------------------
加载顺序:
  require(some_module)的加载顺序:
    如果some_module是一个核心模块,直接加载,结束
    如果some_module以“/”、“./”或“../”开头,按路径加载some_module,结束。
    假设当前目录为current_dir,按路径加载current_dir/node_modules/some_module
      如果加载成功,结束
      如果加载失败,令current_dir为其父目录
      重复这一过程,直到遇到根目录,抛出异常,结束
---------------------------------
循环的陷阱:闭包
---------------------------------
深层的回调函数嵌套:改变设计模式,时刻注意降低逻辑之间的耦合关系
---------------------------------
应用部署:
  日志功能:
    Express支持两种运行模式:开发模式和产品模式,前者的目的是利于调试,后者则是利于部署
    使用产品模式运行服务器的方式很简单,命令行输入:NODE_ENV=production node app.js
    app.js:
      var fs = require('fs');
      var accessLogfile = fs.createWriteStream('access.log', {flags: 'a'});
      var errorLogfile = fs.createWriteStream('error.log', {flags: 'a'});
    app.configure函数第一行加入:
      app.use(express.logger({stream: accessLogfile}));
    错误日志-需要在产品模式中实现错误响应:
      app.configure('production', function(){
        app.use(function(err, req, res, next){
          var meta = '[' + new Date() + '] ' + req.url + '\n';
          errorLogfile.write(meta + err.stack + '\n');
          next();
        });
      });
---------------------------------
多核提高性能及故障恢复:
  Node.js的核心模块child_process:生成与当前进程相同的子进程
  cluster的功能是生成与当前进程相同的子进程,并且允许父进程和子进程之间共享端口
  区别在于cluster允许跨进程端口复用
  为了外部模块能调用app.js,需要禁止服务器自动启动。修改app.js:
    var app = express() --> var app = module.exports = express()
    if (!module.parent) {//判断当前模块是不是由其他模块调用的
        http.createServer(app).listen(3000, function(){
            console.log("Express server listening on port %d in %s mode", 3000, app.settings.env);
        });
    }
  cluster.js的功能是创建与CPU核心个数相同的服务器进程,以确保充分利用多核CPU的资源。通过cluster调用app.js。创建cluster.js:
    var cluster = require('cluster');
    var os = require('os');
    // 获取 CPU 的数量
    var numCPUs = os.cpus().length;
    var workers = {};
    if (cluster.isMaster) {
      // 主进程分支
      cluster.on('death', function (worker) {
        // 当一个工作线程结束时,重新启动一个工作线程
        delete workers[worker.pid];
        worker = cluster.fork();
        workers[worker.pid] = worker;
      });
      // 初始化 CPU 数量相同的工作进程
      for (var i = 0; i < numCPUs; i++) {
        var worker = cluster.fork();
        workers[worker.pid] = worker;
      }
    } else {
      // 工作進进程分支,启动服务器
      var app = require('./app');
      app.listen(3000);
    }
    // 当主进程终止时,关闭所有工作进程
    process.on('SIGTERM', function () {
      for (var pid in workers) {
        process.kill(pid);
      }
      process.exit(0);
    });
---------------------------------
启动脚本:通过nohup启动服务器,使进程不会因为退出终端而关闭
  #! /bin/sh
  NODE_ENV=production
  DAEMON="node cluster.js"
  NAME=Microblog
  DESC=Microblog
  PIDFILE="/usr/works/microblog.pid"
  case "$1" in
    start)
        echo "Starting $DESC: "
        nohup $DAEMON > /usr/works/microblog &
        echo $! > $PIDFILE
        echo "$NAME."
        ;;
    stop)
        echo "Stopping $DESC: "
        pid=`cat $PIDFILE`
        kill $pid
        rm $PIDFILE
        echo "$NAME."
        ;;
    esac
    exit 0
---------------------------------
反向代理:
  Nginx:
    server {
      listen 80;
      server_name microblog.com;
      location / {
        proxy_pass http://localhost:3000;
      }
    }
---------------------------------
Nginx配置文件中添加访问静态文件的规则
  删除app.js中的app.use(express.static(path.join(__dirname, 'public')));

posted @ 2012-12-25 16:04  WenEric  阅读(1197)  评论(0编辑  收藏  举报