1. 技术准备


node.js             我选用的是最新的node-v6.9.2-x64

npm

express            一个简单的Web框架(Express4.x版本)

markdown.js

prettify.js          google-code-prettify, 提供在线的语法高亮支持,支持语法包括C-like, Java, Python, shell等大多


2. 安装node.js


官网下载地址:https://nodejs.org/en/ 找到最新的进行下载。


项目下的node_modules是如何生成的_ico


项目下的node_modules是如何生成的_ico_02



项目下的node_modules是如何生成的_Express_03


项目下的node_modules是如何生成的_nodejs_04



项目下的node_modules是如何生成的_nodejs_05


在cmd下运行"node -v"查看是否安装成功


项目下的node_modules是如何生成的_Express_06


3. 配置npm


由于新版的NodeJS已经集成了npm,所以之前npm也一并安装好了。同样可以使用cmd命令行输入"npm -v"来测试是否成功安装。如下图,出现版本提示便OK了。


项目下的node_modules是如何生成的_ico_07


配置淘宝镜像


前往淘宝镜像官网 http://npm.taobao.org/,可查看安装cnpm包的命令

在命令行输入:


npm install -g cnpm --registry=https://registry.npm.taobao.org


项目下的node_modules是如何生成的_nodejs_08



安装完成


npm install -g cnpm --registry=https://registry.npm.taobao.org


项目下的node_modules是如何生成的_ico_09



或者通过: 


npm config set registry https://registry.npm.taobao.org 


设置淘宝的registry,通过:


npm info underscore (如果上面配置正确这个命令会有字符串response)


项目下的node_modules是如何生成的_ico_10



4. node的express框架


Express 是一个简洁而灵活的 node.js Web应用框架, 提供了一系列强大特性帮助你创建各种 Web 应用,和丰富的 HTTP 工具。


使用 Express 可以快速地搭建一个完整功能的网站。

Express 框架核心特性:

----可以设置中间件来响应 HTTP 请求。
----定义了路由表用于执行不同的 HTTP 请求动作。
----可以通过向模板传递参数来动态渲染 HTML 页面。


在CMD下输入: $ npm install express --save


项目下的node_modules是如何生成的_ico_11


以上命令会将 Express 框架安装在当前目录的 node_modules 目录中, node_modules 目录下会自动创建 express 目录。以下几个重要的模块是需要与 express 框架一起安装的:


----body-parser - node.js 中间件,用于处理 JSON, Raw, Text 和 URL 编码的数据。

----cookie-parser - 这就是一个解析Cookie的工具。通过req.cookies可以取到传过来的cookie,并把它们转成对象。

----multer - node.js 中间件,用于处理 enctype="multipart/form-data"(设置表单的MIME编码)的表单数据。


$ npm install body-parser --save
$ npm install cookie-parser --save
$ npm install multer --save


项目下的node_modules是如何生成的_nodejs_12


项目下的node_modules是如何生成的_ico_13


项目下的node_modules是如何生成的_Express_14


测试是否安装成功: express -v #看看是否安装成功


项目下的node_modules是如何生成的_ico_15


创建一个express项目看看


初始化一个 express 项目并安装所需模块


express -e blog  


项目下的node_modules是如何生成的_nodejs_16


进入到刚刚创建的那个目录: cd blog


express目录结构

项目下的node_modules是如何生成的_ico_17


Express 目录结构

目录/文件

说明

./

根目录,我们的node.js代码都会方这个目录

package.json 

npm依赖配置文件, 类似ruby中的Gemfile, java Maven中的pom.xml文件. 一会需要在这里添加 markdown-js 项目依赖

app.js

项目的入口文件

public/

javascrip t/

stylesheets/

images/

存放静态资源文件, jquery/prettify.js等静态库会方这里,当然自己编写的前端代码也可以放这里

views/

模板文件, express默认采用jade, 当然,你也可以使用自己喜欢的haml,JES, coffeeKup, jQueryTemplate等模板引擎

node_modules/

存放npm安装到本地依赖包,依赖包在package.json文件中声明,使用npm install指令安装


运行程序看看


$ npm install


项目下的node_modules是如何生成的_nodejs_18


然后运行:

npm start


项目下的node_modules是如何生成的_ico_19


访问: http://localhost:3000/


项目下的node_modules是如何生成的_node.js_20


至此,用 express 初始化了一个工程项目,并指定使用 ejs 模板引擎。


我们看看app.js文件的内容:


var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');

var index = require('./routes/index');
var users = require('./routes/users');

var app = express();

// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');

// uncomment after placing your favicon in /public
//app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));

app.use('/', index);
app.use('/users', users);

// catch 404 and forward to error handler
app.use(function(req, res, next) {
  var err = new Error('Not Found');
  err.status = 404;
  next(err);
});

// error handler
app.use(function(err, req, res, next) {
  // set locals, only providing error in development
  res.locals.message = err.message;
  res.locals.error = req.app.get('env') === 'development' ? err : {};

  // render the error page
  res.status(err.status || 500);
  res.render('error');
});

module.exports = app;



这里通过require()加载了express、path 等模块,以及 routes 文件夹下的index. js和 users.js 路由文件。 下面来讲解每行代码的含义。


(1) var app = express():生成一个express实例 app。


(2)app.set('views', path.join(__dirname, 'views’)):设置 views 文件夹为存放视图文件的目录, 即存放模板文件的地方,__dirname 为全局变量,存储当前正在执行的脚本所在的目录。


(3)app.set('view engine', 'ejs’):设置视图模板引擎为 ejs。


(4)app.use(favicon(__dirname + '/public/favicon.ico’)):设置/public/favicon.ico为favicon图标。


(5)app.use(logger('dev’)):加载日志中间件。


(6)app.use(bodyParser.json()):加载解析json的中间件。


(7)app.use(bodyParser.urlencoded({ extended: false })):加载解析urlencoded请求体的中间件。


(8)app.use(cookieParser()):加载解析cookie的中间件。


(9)app.use(express.static(path.join(__dirname, 'public'))):设置public文件夹为存放静态文件的目录。


(10)app.use('/', routes);和app.use('/users', users):路由控制器。


(11)


app.use(function(req, res, next) {
    var err = new Error('Not Found');
    err.status = 404;
    next(err);
});



捕获404错误,并转发到错误处理器。



(12)


if (app.get('env') === 'development') {
    app.use(function(err, req, res, next) {
        res.status(err.status || 500);
        res.render('error', {
            message: err.message,
            error: err
        });
    });
}



开发环境下的错误处理器,将错误信息渲染error模版并显示到浏览器中。



(13)


app.use(function(err, req, res, next) {
    res.status(err.status || 500);
    res.render('error', {
        message: err.message,
        error: {}
    });
});

生产环境下的错误处理器,将错误信息渲染error模版并显示到浏览器中。


(14)

module.exports = app :导出app实例供其他模块调用。


我们再看 bin/www 文件:



#!/usr/bin/env node
var debug = require('debug')('blog');
var app = require('../app');

app.set('port', process.env.PORT || 3000);

var server = app.listen(app.get('port'), function() {
  debug('Express server listening on port ' + server.address().port);
});



(1)#!/usr/bin/env node:表明是 node 可执行文件。


(2)var debug = require('debug')('blog’):引入debug模块,打印调试日志。


(3)var app = require('../app’):引入我们上面导出的app实例。


(4)app.set('port', process.env.PORT || 3000):设置端口号。


(5)



var server = app.listen(app.get('port'), function() {
  debug('Express server listening on port ' + server.address().port);
});



启动工程并监听3000端口,成功后打印 Express server listening on port 3000。


我们再看 routes/index.js 文件:



var express = require('express');
var router = express.Router();

/* GET home page. */
router.get('/', function(req, res) {
  res.render('index', { title: 'Express' });
});

module.exports = router;



生成一个路由实例用来捕获访问主页的GET请求,导出这个路由并在app.js中通过app.use('/', routes); 加载。这样,当访问主页时,就会调用res.render('index', { title: 'Express' });渲染views/index.ejs模版并显示到浏览器中。


我们再看看 views/index.ejs 文件:



<!DOCTYPE html>
<html>
  <head>
    <title><%= title %></title>
    <link rel='stylesheet' href='/stylesheets/style.css' />
  </head>
  <body>
    <h1><%= title %></h1>
    <p>Welcome to <%= title %></p>
  </body>
</html>



在渲染模板时我们传入了一个变量 title 值为 express 字符串,模板引擎会将所有 <%= title %> 替换为 express ,然后将渲染后生成的html显示到浏览器中,如上图所示。


在这一小节我们学习了如何创建一个工程并启动它,了解了工程的大体结构和运作流程,下一小节我们将学习 express 的基本使用及路由控制。



5.路由控制


工作原理

routes/index.js 中有以下代码:


router.get('/', function(req, res){
  res.render('index', { title: 'Express' });
});



这段代码的意思是当访问主页时,调用 ejs 模板引擎,来渲染 index.ejs 模版文件(即将 title 变量全部替换为字符串 Express),生成静态页面并显示在浏览器中。


我们来作一些修改,以上代码实现了路由的功能,我们当然可以不要 routes/index.js 文件,把实现路由功能的代码都放在 app.js 里,但随着时间的推移 app.js 会变得臃肿难以维护,这也违背了代码模块化的思想,所以我们把实现路由功能的代码都放在 routes/index.js 里。官方给出的写法是在 app.js 中实现了简单的路由分配,然后再去 index.js 中找到对应的路由函数,最终实现路由功能。我们不妨把路由控制器和实现路由功能的函数都放到 index.js 里,app.js 中只有一个总的路由接口。


最终将 app.js 修改为:



var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');

var routes = require('./routes/index');

var app = express();

app.set('port', process.env.PORT || 3000);
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');

//app.use(favicon(__dirname + '/public/favicon.ico'));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));

routes(app);

app.listen(app.get('port'), function() {
  console.log('Express server listening on port ' + app.get('port'));
});


修改 index.js 如下:



module.exports = function(app) {
  app.get('/', function (req, res) {
    res.render('index', { title: 'Express' });
  });
};



现在,再运行你的 app,你会发现主页毫无二致。这里我们在 routes/index.js 中通过 module.exports 导出了一个函数接口,在 app.js 中通过  require 加载了 index.js 然后通过 routes(app) 调用了 index.js 导出的函数。



路由规则


express 封装了多种 http 请求方式,我们主要只使用 get 和  post 两种,即  app.get() 和 app.post() 。

app.get() 和  app.post() 的第一个参数都为请求的路径,第二个参数为处理请求的回调函数,回调函数有两个参数分别是 req 和 res,代表请求信息和响应信息 。路径请求及对应的获取路径有以下几种形式:


req.query


// GET /search?q=tobi+ferret  
req.query.q  
// => "tobi ferret"  

// GET /shoes?order=desc&shoe[color]=blue&shoe[type]=converse  
req.query.order  
// => "desc"  

req.query.shoe.color  
// => "blue"  

req.query.shoe.type  
// => "converse"




req.body


// POST user[name]=tobi&user[email]=tobi@learnboost.com  
req.body.user.name  
// => "tobi"  

req.body.user.email  
// => "tobi@learnboost.com"  

// POST { "name": "tobi" }  
req.body.name  
// => "tobi"



req.params



// GET /user/tj  
req.params.name  
// => "tj"  

// GET /file/javascripts/jquery.js  
req.params[0]  
// => "javascripts/jquery.js"



req.param(name)



// ?name=tobi  
req.param('name')  
// => "tobi"  

// POST name=tobi  
req.param('name')  
// => "tobi"  

// /user/tobi for /user/:name   
req.param('name')  
// => "tobi"



不难看出:


----req.query : 处理 get 请求,获取 get 请求参数
----req.params : 处理 /:xxx 形式的 get 或 post 请求,获取请求参数
----req.body : 处理 post 请求,获取 post 请求体
----req.param() : 处理 get 和 post 请求,但查找优先级由高到低为 req.params→req.body→req.query


添加路由规则

当我们访问 localhost:3000 时,会显示:


项目下的node_modules是如何生成的_node.js_20


当我们访问 localhost:3000/fendo 这种不存在的页面时就会显示:


项目下的node_modules是如何生成的_nodejs_22

这是因为不存在 /fendo 的路由规则,而且它也不是一个 public 目录下的文件,所以 express 返回了 404 Not Found 的错误。下面我们来添加这条路由规则,使得当访问 localhost:3000/fendo 时,页面显示 hello,world!

注意:以下修改仅用于测试,看到效果后再把代码还原回来。

修改 index.js,在 app.get('/') 函数后添加一条路由规则:



router.get('/fendo', function (req, res) {
  res.send('hello,world!');
});


项目下的node_modules是如何生成的_ico_23




重启之后,访问 localhost:3000/fendo 页面显示如下:



项目下的node_modules是如何生成的_ico_24