12_Node.js Web 开发_博客网站

下面开始用 Node.js 进行 Web 开发。css

我是经过《Node.js开发指南》这本书来学习 Node.js Web 开发的,书中使用的 Express 框架是 2.5.8,而个人是 4.14.1,因此遇到了许多问题,在文章中我都有提到并讲解。html

GitHub 地址前端

1、快速开始

一、创建项目

《Node.js开发指南》中创建项目的方式是:express -t ejs microblog,可是这种方式对于高版本的 Express 新建的标签替换引擎并非 .ejs,而是 .jade,若是要使用 .ejs 咱们能够经过下面命令创建网站基本结构。node

express -e NodeJSBlog
复制代码

执行命令后在当前目录下出现了一些文件,而且下边提示咱们经过 npm install 安装依赖。jquery

在 npm install 以后,打开 NodeJSBlog 目录下的 package.json,能够看到已安装的包及对应的版本号。git

二、启动服务器

注意,咱们以前开启 Node.js 服务器,都是执行 node xxx.js,而后去浏览器访问便可,可是 Express 4.x 以上就不是这种方式了,应该是 npm start,端口配置在 bin/www 中。github

启动成功访问 localhost:3000/。正则表达式

三、项目结构

咱们看一下 express 在 NodeJSBlog 这个目录下都生成了哪些文件。mongodb

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;
复制代码

app.js 是项目的入口,首先引入了一系列咱们所须要的模块,而后引入了 routes 目录下的两个本地模块,它的功能是为指定路径组织返回内容,至关于 MVC 架构中的控制器。数据库

接下来是视图引擎设置, app.set() 是 Express 的参数设置工具,接受一个键(key)和一个值(value),可用的参数以下所示:

  • basepath:基础地址,一般用于 res.redirect() 跳转。
  • views:视图文件的目录,存放模板文件。
  • view engine:视图模板引擎。
  • view options:全局视图参数对象。
  • view cache:启用视图缓存。
  • case sensitive routes:路径区分大小写。
  • strict routing:严格路径,启用后不会忽略路径末尾的“ / ”。
  • jsonp callback:开启透明的 JSONP 支持

Express 依赖于 connect,提供了大量的中间件,能够经过 app.use() 启用

routes/index.js
var express = require('express');
var router = express.Router();

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

module.exports = router;
复制代码

routes/index.js 是路由文件,至关于控制器,用于组织展现的内容,app.js 中经过 app.get('/', routes.index); 将“ / ”路径映射到 exports.index 函数下,其中只有一个语句 res.render('index', { title: 'Express' }),功能是调用模板解析引擎,翻译名为 index 的模板,并传入一个对象做为参数,这个对象只有一个属性,即 title: 'Express'。

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>
复制代码

index.ejs 是模板文件,即 routes/index.js 中调用的模板,内容是:

<h1><%= title %></h1>
<p>Welcome to <%= title %></p>
复制代码

它的基础是 HTML 语言,其中包含了形如 <%= title %> 的标签,功能是显示引用的变量,即 res.render 函数第二个参数传入的对象的属性。

补充 include

在书中 views 目录下是有 layout.ejs 的,它可让全部模板去继承它,<%- body %> 中是独特的内容,其余部分是共有的,能够看做是页面框架。

书中 layout.ejs:

<head>
    <title>
        <%= title %>
    </title>
    <link rel='stylesheet' href='/stylesheets/style.css' />
</head>

<body>
    <%- body %>
</body>

</html>
复制代码

可是 Express 4.x 就没有 layout.ejs 了,解决方法:

官方推荐了 include 方式,它不只能实现 layout 的功能,仍是将 view 的那些可复用的 html 片断提取成模块,在须要使用的地方直接用 <% include xxx %>。

例如先在 views 目录下新建一个 public_file.ejs ,在里面添加须要引用的公共文件:

<link rel='stylesheet' href='/stylesheets/style.css' />
复制代码

而后修改一下 index.ejs,使用 <% include listitem %> 方式引用上边公共文件:

<!DOCTYPE html>
<html>
  <head>
    <title><%= title %></title>
    <% include public_file %>
  </head>
  <body>
    <h1><%= title %></h1>
    <p>Welcome to <%= title %></p>
  </body>
</html>
复制代码

重启服务,访问 localhost:3000/,能够看到 style.css 文件正常引用。

每一次修改咱们都须要重启服务才能看到修改后的结果,您能够看个人《Node.js 应用程序自动重启》这篇文章去安装 supervisor 或 nodemon 两个插件来实现应用程序自动重启。

2、路由控制

一、建立页面路由

简单说一下新增一个页面的流程。

首先在 views 目录下新建一个模板,例如 hello.ejs:

而后打开 index.js 文件,添加页面路由信息:

访问 localhost:3000/hello。

补充:在《Node.js开发指南》这本书中,还须要向 app.js 文件中添加页面路由信息,但在 Express 4.x 中是不须要的。

二、路径匹配

上面的例子是为固定的路径设置路由规则,Express 还支持更高级的路径匹配模式,例如咱们想要展现一个用户的我的页面,路径为 /user/[username],能够用下面的方法定义路由 规则:

router.get('/user/:username', function(req, res, next) {
    res.send('user: ' + req.params.username);
});
复制代码

重启项目,访问 localhost:3000/user/LiuZhenghe。

注意:调用模板解析引擎,用 res.render(),只是向页面发送数据,用 res.send()。

路径规则 /user/:username 会被自动编译为正则表达式,相似于 /user/([^/]+)/? 这样的形式,路径参数能够在响应函数中经过 req.params 的属性访问。

路径规则一样支持 JavaScript 正则表达式,例如 app.get(/user/([^/]+)/?,callback),这样的好处在于能够定义更加复杂的路径规则,而不一样之处是匹配的参数是匿名的,所以须要经过 req.params[0]、req.params[1] 这样的形式访问。

三、REST 风格的路由规则

Express 支持 REST 风格的请求方式,在介绍以前咱们先说明一下什么是 REST。

REST 的意思是表征状态转移(Representational State Transfer),它是一种基于 HTTP 协议的网络应用的接口风格,充分利用 HTTP 的方法实现统一风格接口的服务。

HTTP 协议定义了如下 8 种标准的方法:

  • GET:请求获取指定资源。
  • HEAD:请求指定资源的响应头。
  • POST:向指定资源提交数据。
  • PUT:请求服务器存储一个资源。
  • DELETE:请求服务器删除指定资源。
  • TRACE:回显服务器收到的请求,主要用于测试或诊断。
  • CONNECT:HTTP/1.1 协议中预留给可以将链接改成管道方式的代理服务器。
  • OPTIONS:返回服务器支持的HTTP请求方法。

其中咱们常常用到的是 GET、POST、PUT 和 DELETE 方法,根据 REST 设计模式,这4种方法一般分别用于实现如下功能。

  • GET:获取
  • POST:新增
  • PUT:更新
  • DELETE:删除

这是由于这 4 种方法有不一样的特色,按照定义,它们的特色以下表所示:

请求方式 安全 幂等
GET
POST
PUT
DELETE

所谓安全是指没有反作用,即请求不会对资源产生变更,连续访问屡次所得到的结果不受访问者的影响,而幂等指的是重复请求屡次与一次请求的效果是同样的,好比获取和更新操做是幂等的,这与新增不一样,删除也是幂等的,即重复删除一个资源,和删除一次是同样的。

Express 对每种 HTTP 请求方法都设计了不一样的路由绑定函数,例如前面例子所有是 app.get,表示为该路径绑定了 GET 请求,向这个路径发起其余方式的请求不会被响应。

下表是 Express 支持的全部 HTTP 请求的绑定函数。

请求方式 绑定函数
GET app.get(path, callback)
POST app.post(path, callback)
PUT app.put(path, callback)
DELETE app.delete(path, callback)
PATCH app.patch(path, callback)
TRACE app.trace(path, callback)
CONNECT app.connect(path, callback)
OPTIONS app.options(path, callback)
全部方法 app.all(path, callback)

例如咱们要绑定某个路径的 POST 请求,则能够用 app.post(path, callback) 的 方法,须要注意的是 app.all 函数,它支持把全部的请求方式绑定到同一个响应函数,是一个很是灵活的函数,在后面咱们能够看到许多功能均可以经过它来实现。

四、控制权转移

Express 支持同一路径绑定多个路由响应函数,例如:

index.js

// ...
/* 路径匹配模式 */
router.all('/user/:username', function(req, res, next) {
    res.send('all methods captured');
});

router.get('/user/:username', function(req, res, next) {
    res.send('user: ' + req.params.username);
});
// ...
复制代码

当再次访问 localhost:3000/user/LiuZhenghe 时,发现页面被第一条路由规则捕获。

缘由是 Express 在处理路由规则时,会优先匹配先定义的路由规则,所以后面相同的规则被屏蔽。

Express 提供了路由控制权转移的方法,即回调函数的第三个参数 next,经过调用 next(),会将路由控制权转移给后面的规则,例如:

// ...
/* 路径匹配模式 */
router.all('/user/:username', function(req, res, next) {
    console.log('all methods captured');
    next();
});

router.get('/user/:username', function(req, res, next) {
    res.send('user: ' + req.params.username);
});
// ...
复制代码

此时刷新页面,在控制台能够看到“all methods captured”,浏览器显示了 user: LiuZhenghe。

这是一个很是有用的工具,可让咱们轻易地实现中间件,并且还能提升代码的复用程度,例如咱们针对一个用户查询信息和修改信息的操做,分别对应了 GET 和 PUT 操做,而二者共有的一个步骤是检查用户名是否合法,所以能够经过 next() 方法实现。

3、模板引擎

模板引擎也就是视图,视图决定了用户最终能看到什么,这里咱们用 ejs 为例介绍模板引擎的使用方法。

一、使用模板引擎

在 app.js 中,如下两句设置了模板引擎和页面模板的位置:

app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
复制代码

在 index.js 中经过 res.render() 调用模板,res.render() 的功能是调用模板引擎,并将其产生的页面直接返回给客户端,它接受两个参数,第一个是模板的名称,即 views 目录下的模板文件名,不包含文件的扩展名;第二个参数是传递给模板的数据,用于模板翻译。

ejs 的标签系统很是简单,它只有如下 3 种标签:

  • <% code %>:JavaScript 代码。
  • <%= code %>:显示替换过 HTML 特殊字符的内容。
  • <%- code %>:显示原始 HTML 内容。

咱们能够用它们实现页面模板系统能实现的任何内容。

二、片断视图

《Node.js开发指南》中所讲的片断视图(partials)在 Express 4.x 中已经不支持了,在上面项目结构分析那一节中我曾补充过 include,这里再次介绍一下它的用法。

官方推荐了 include 方式,它不只能实现 layout 的功能,仍是将 view 的那些可复用的 html 片断提取成模块,在须要使用的地方直接用 <% include xxx %>,看下面这个例子:

首先在 index.js 中新增如下内容:

// 片段视图
router.get('/list', function(reg, res) {
    res.render('list', {
        title: "List",
        items: [2019, 'Node.js', 'NodeJSBlog', 'Express']
    });
});
复制代码

而后新建 list.ejs 文件并添加如下内容:

<ul>
<% items.forEach(function(listitem){ %>
<% include listitem %>
<% }) %>
</ul>
复制代码

同时新建 listitem.ejs 文件并添加:

<li><%= listitem %></li>
复制代码

访问 localhost:3000/list,能够看到如下内容:

4、开始创建博客网站

一、功能分析

博客网站首先应该有登陆注册功能,而后是最核心的功能——信息发表,这个功能涉及到许多方面,包括数据库访问,前端显示等。

一个完整的博客系统,应该有评论,收藏,转发等功能,处于本人目前的能力水平还不能都实现,先作一个博客网站的雏形吧。

二、路由规划

根据功能设计,咱们把路由按照如下方案规划:

  • /:首页
  • /u/[user]:用户的主页
  • /post:发表信息
  • /reg:用户注册
  • /login:用户登陆
  • /logout:用户登出

以上页面还能够根据用户状态细分,发表信息以及用户登出页面必须是已登陆用户才能操做的功能,而用户注册和用户登入所面向的对象必须是未登入的用户,首页和用户主页则针对已登入和未登入的用户显示不一样的内容。

在 index.js 中添加如下内容:

router.get('/', function(req, res) {
    res.render('index', {
        title: 'Express'
    });
});
router.get('/u/:user', function(req, res) {});
router.post('/post', function(req, res) {});
router.get('/reg', function(req, res) {});
router.post('/reg', function(req, res) {});
router.get('/login', function(req, res) {});
router.post('/login', function(req, res) {});
router.get('/logout', function(req, res) {});
复制代码

其中 /post、/login 和 /reg 因为要接受表单信息,所以使用 router.post 注册路由,/login 和 /reg 还要显示用户注册时要填写的表单,因此要以 router.get 注册。

三、使用 Bootstrap

下载 jquery.js,bootstrap.css 和 bootstrap.js,放到 public 下对应的目录中。

在 public_file.ejs 中引用,可使用 include 方法给模板添加公共文件。

Bootstrap官网 查看并使用所需的模板或组件。

下图是我从 Bootstrap 官网找的一个模板,并放到了 index.ejs 目录下并进行了简单地修改,并将页面公共部分(头尾部分)取出,用 include 方式来复用。

5、用户注册和登陆

一、访问数据库

咱们选用 MongoDB 做为网站的数据库系统,它是一个开源的 NoSQL 数据库,相比 MySQL 那样的关系型数据库,它更为轻巧、灵活,很是适合在数据规模很大、事务性不强的场合下使用。

链接数据库

经过 npm 安装 mongodb。

npm install mongodb --save
复制代码

补充:经过 --save 安装,包名和版本号将会出如今 package.json 中。

接下来在项目主目录中建立 settings.js 文件,这个文件用于保存数据库的链接信息,咱们将用到的数据库命名为 NodeJSBlog,数据库服务器在本地,所以 settings.js 文件的内容以下:

settings.js

module.exports = {
    cookieSecret: 'NodeJSBlogbyvoid',
    db: 'NodeJSBlog',
    host: 'localhost',
};
复制代码

其中,db 是数据库的名称,host 是数据库的地址,cookieSecret 用于 Cookie 加密与数据库无关,咱们留做后用。

接下来新建 models 目录,并在目录中建立 db.js:

models/db.js

var settings = require('../settings'),
    Db = require('mongodb').Db,
    Connection = require('mongodb').Connection,
    Server = require('mongodb').Server;
module.exports = new Db(settings.db, new Server(settings.host, 27017, {}), {
    safe: true
});
复制代码

以上代码经过 module.exports 输出了建立的数据库链接,在后面的小节中咱们会用到这个模块,因为模块只会被加载一次,之后咱们在其余文件中使用时均为这一个实例。

二、会话支持

《Node.js开发指南》中对会话支持是这样描述的:

会话是一种持久的网络协议,用于完成服务器和客户端之间的一些交互行为。会话是一个比链接粒度更大的概念,一次会话可能包含屡次链接,每次链接都被认为是会话的一次操做。在网络应用开发中,有必要实现会话以帮助用户交互。例如网上购物的场景,用户浏览了多个页面,购买了一些物品,这些请求在屡次链接中完成。许多应用层网络协议都是由会话支持的,如 FTP、Telnet 等,而 HTTP 协议是无状态的,自己不支持会话,所以在没有额外手段的帮助下,前面场景中服务器不知道用户购买了什么。

为了在无状态的 HTTP 协议之上实现会话,Cookie 诞生了。Cookie 是一些存储在客户端的信息,每次链接的时候由浏览器向服务器递交,服务器也向浏览器发起存储 Cookie 的请求,依靠这样的手段服务器能够识别客户端。咱们一般意义上的 HTTP 会话功能就是这样实现的。具体来讲,浏览器首次向服务器发起请求时,服务器生成一个惟一标识符并发送给客户端浏览器,浏览器将这个惟一标识符存储在 Cookie 中,之后每次再发起请求,客户端浏览器都会向服务器传送这个惟一标识符,服务器经过这个惟一标识符来识别用户。

对于开发者来讲,咱们无须关心浏览器端的存储,须要关注的仅仅是如何经过这个惟一标识符来识别用户。不少服务端脚本语言都有会话功能,如 PHP,把每一个惟一标识符存储到文件中。Express 也提供了会话中间件,默认状况下是把用户信息存储在内存中,但咱们既然已经有了 MongoDB,不妨把会话信息存储在数据库中,便于持久维护。

可是若是你的 Express 版本是 4.x,按照书中接下来的内容编写代码,就会出各类问题,下面我来讲一下 Express 4.x 中的会话支持。

在 Express 4.x 中咱们须要本身安装 express-session 包,而后添加引用:

var session = require('express-session');
复制代码

而后再引用 connect-mongo 包:

var MongoStore = require('connect-mongo')(session);
复制代码

最终在 app.js 中新增的内容就是:

var settings = require('./settings');
var session = require('express-session');
var MongoStore = require('connect-mongo')(session);
app.use(session({
    secret: settings.cookieSecret,
    store: new MongoStore({
        db: settings.db,
    })
}));
复制代码

可是此时程序会报错:'Connection strategy not found':

从网上查找到该问题以后找到了解决办法,打开 package.json 文件,将 connect-mongo 的版本改成 0.8.2,而后执行 npm install 便可解决。

若是程序没有报错,那么就成功了,你可使用 mongo.exe 或可视化工具来查看数据库是否新建成功。

三、注册和登陆

3.一、注册

经过可视化工具或 mongodb 终端新建一个用户表 users。

注册页面:

首先添加注册页面的模板 views/reg.ejs,并添加表单结构:

<div class="container">
    <div class="bs-example" data-example-id="basic-forms">
        <form>
            <div class="form-group">
                <label for="username">用户名</label>
                <input type="text" class="form-control" id="username" placeholder="请输入用户名">
            </div>
            <div class="form-group">
                <label for="password">密码</label>
                <input type="password" class="form-control" id="password" placeholder="请输入密码">
            </div>
            <div class="form-group">
                <label for="password_repeat">再次输入密码</label>
                <input type="password" class="form-control" id="password_repeat" placeholder="再次输入密码">
            </div>
            <button type="submit" class="btn btn-default">注册</button>
        </form>
    </div>
</div>
复制代码

而后打开 index.js 添加注册页面的路由信息:

index.js

router.get('/reg', function(req, res) {
    res.render('reg', {
        title: '用户注册'
    });
});
复制代码

而后访问 localhost:3000/reg。

注册响应:

在书中使用了 flash,可是最新版本的 Express 已经不支持 flash 了,你须要先经过 npm 安装 connect-flash。

而后在 app.js 中添加以下代码:

var flash = require('connect-flash');
复制代码

在 routes/index.js 中添加 /reg 的 POST 响应函数:

routes/index.js

// 注册响应
var crypto = require('crypto');
var User = require('../models/user.js');
var MongoClient = require('mongodb').MongoClient;
const DB_CONN_STR='mongodb://localhost:27017/users';
router.post('/reg', function(req, res) {
    let newUser = {
        username: req.body.username,
        password: req.body.password,
        password_repeat: req.body.password_repeat
    };
    let addStr = [{
        username: newUser.username,
        password: newUser.password
    }];
    MongoClient.connect(DB_CONN_STR, function(err, db) {
        db.collection('users').findOne({
            username: newUser.username
        }, function(err, result) {
            if (!result) {
                if (newUser.password === newUser.password_repeat) {
                    MongoClient.connect(DB_CONN_STR, function(err, db) {
                        req.session.error = '注册成功,请登陆!';
                        db.collection('users').insert(addStr);
                        db.close();
                        return res.redirect('/login');
                    });
                } else {
                    req.session.error = '两次密码不一致!';
                    return res.redirect('/register');
                }
            } else {
                req.session.error = '用户名已存在!';
                return res.redirect('/register');
            }
        })
        db.close();
    });
});

复制代码
  • req.body 就是 POST 请求信息解析事后的对象,例如咱们要访问用户传递的 password 域的值,只需访问 req.body['password'] 便可。
  • req.flash 是 Express 提供的一个奇妙的工具,经过它保存的变量只会在用户当前和下一次的请求中被访问,以后会被清除,经过它咱们能够很方便地实现页面的通知和错误信息显示功能。
  • res.redirect 是重定向功能,经过它会向用户返回一个 303 See Other 状态,通知浏览器转向相应页面。
  • crypto 是 Node.js 的一个核心模块,功能是加密并生成各类散列,使用它以前首先要声明 var crypto = require('crypto'),咱们代码中使用它计算了密码的散列值。
  • User 是咱们设计的用户对象,在后面咱们会详细介绍,这里先假设它的接口都是可用的,使用前须要经过 var User = require('../models/user.js') 引用。
  • User.get 的功能是经过用户名获取已知用户,在这里咱们判断用户名是否已经存在,User.save 能够将用户对象的修改写入数据库。
  • 经过 req.session.user = newUser 向会话对象写入了当前用户的信息,在后面咱们会经过它判断用户是否已经登陆。

用户模型

在前面的代码中,咱们直接使用了 User 对象,User 是一个描述数据的对象,即 MVC 架构中的模型,前面咱们使用了许多视图和控制器,这是第一次接触到模型。与视图和控制器不一样,模型是真正与数据打交道的工具,没有模型,网站就只是一个外壳,不能发挥真实的做用,所以它是框架中最根本的部分。如今就让咱们来实现 User 模型吧。

在 models 目录中建立 user.js 的文件,内容以下:

models/user.js

var mongodb = require('./db');

function User(user) {
    this.name = user.name;
    this.password = user.password;
};
module.exports = User;
User.prototype.save = function save(callback) {
    // 存入 Mongodb 的文档
    var user = {
        name: this.name,
        password: this.password,
    };
    mongodb.open(function(err, db) {
        if (err) {
            return callback(err);
        }
        // 读取 users 集合
        db.collection('users', function(err, collection) {
            if (err) {
                mongodb.close();
                return callback(err);
            }
            // 为 name 属性添加索引
            collection.ensureIndex('name', {
                unique: true
            });
            // 写入 user 文档
            collection.insert(user, {
                safe: true
            }, function(err, user) {
                mongodb.close();
                callback(err, user);
            });
        });
    });
};

User.get = function get(username, callback) {
    mongodb.open(function(err, db) {
        if (err) {
            return callback(err);
        }
        // 读取 users 集合
        db.collection('users', function(err, collection) {
            if (err) {
                mongodb.close();
                return callback(err);
            }
            // 查找 name 属性为 username 的文档
            collection.findOne({
                name: username
            }, function(err, doc) {
                mongodb.close();
                if (doc) {
                    // 封装文档为 User 对象
                    var user = new User(doc);
                    callback(err, user);
                } else {
                    callback(err, null);
                }
            });
        });
    });
};
复制代码

以上代码实现了两个接口,User.prototype.save 和 User.get,前者是对象实例的方法,用于将用户对象的数据保存到数据库中,后者是对象构造函数的方法,用于从数据库中查找指定的用户。

视图交互

如今几乎已经万事俱备,只差视图的支持了。为了实现不一样登陆状态下页面呈现不一样内容的功能,咱们须要建立动态视图助手,经过它咱们才能在视图中访问会话中的用户数据,同时为了显示错误和成功的信息,也要在动态视图助手中增长响应的函数。

在书中,在 app.js 中添加的视图交互代码是:

app.dynamicHelpers({
    user: function(req, res) {
        return req.session.user;
    },
    error: function(req, res) {
        var err = req.flash('error');
        if (err.length)
            return err;
        else
            return null;
    },
    success: function(req, res) {
        var succ = req.flash('success');
        if (succ.length)
            return succ;
        else
            return null;
    },
});
复制代码

可是在 Express 4.x 中会报错“app.dynamicHelpers is not a function ”,此处应该添加:

app.js

app.use(flash());
app.use(function(req, res, next) {
    res.locals.user = req.session.user;
    res.locals.post = req.session.post;
    var error = req.flash('error');
    res.locals.error = error.length ? error : null;
    var success = req.flash('success');
    res.locals.success = success.length ? success : null;
    next();
});
复制代码

注意,这段代码不要放的太靠后,应该放到路由控制代码以前。

接下来修改公共导航部分。

header.ejs

<nav class="navbar navbar-inverse">
    <div class="container">
        <div class="navbar-header">
            <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
                <span class="sr-only"></span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
            </button>
            <a class="navbar-brand" href="/">NodeJS Blog</a>
        </div>
        <div id="navbar" class="navbar-collapse collapse">
            <form class="navbar-form navbar-right">
                <% if (!user) { %>
                <a href="/login" type="submit" class="btn btn-success">登陆</a>
                <a href="/reg" type="submit" class="btn btn-success">注册</a>
                <% } else { %>
                <a href="" type="submit" class="btn">注销</a>
                <% } %>
            </form>
        </div>
    </div>
</nav>
复制代码

而后打开注册页,输入用户名、密码,点击注册按钮,发现又遇到坑了...“db.collection is not a function”。

引发这个错误的缘由是你经过 npm 安装的 mongodb 的版本和你 Node.js 操做数据的 api 版本不一致,查看了一下 package.json,发现 mongodb 的版本是 3.1.13。

解决方法,下载低版本 mongodb,例:

"mongodb": "^2.2.33",
复制代码

npm install 安装。

未完待续......


期待您的关注!

相关文章
相关标签/搜索