JS是腳本語言,腳本語言都需要一個解析器才能運行。對於寫在HTML頁面裏的JS,瀏覽器充當瞭解析器的角色。而對於需要獨立運行的JS,NodeJS就是一個解析器。每一種解析器都是一個運行環境,不但允許JS定義各種數據結構,進行各種計算,還允許JS使用運行環境提供的內置對象和方法做一些事情。例如運行在瀏覽器中的JS的用途是操作DOM,瀏覽器就提供了document之類的內置對象。而運行在NodeJS中的JS的用途是操作磁盤文件或搭建HTTP服務器,NodeJS就相應提供了fs、http等內置對象。Express作爲NodeJS的Web應用框架,可以幫助我們快速開發Web網站。
開發環境
NodeJS:v0.10.30 npm:1.4.21 OS:Win7旗艦版 32bit Express:4.2.0 MongoDB:2.6.3E:\project> node -v
v0.10.30
E:\project> npm -v
1.4.21
E:\project> express -V
4.2.0
1、建立工程
使用express命令建立工程,並支持ejs:
E:\project> express -e nodejs-demo
create : nodejs-demo
create : nodejs-demo/package.json
create : nodejs-demo/app.js
create : nodejs-demo/public
create : nodejs-demo/public/javascripts
create : nodejs-demo/public/images
create : nodejs-demo/public/stylesheets
create : nodejs-demo/public/stylesheets/style.css
create : nodejs-demo/routes
create : nodejs-demo/routes/index.js
create : nodejs-demo/routes/users.js
create : nodejs-demo/views
create : nodejs-demo/views/index.ejs
create : nodejs-demo/views/error.ejs
create : nodejs-demo/bin
create : nodejs-demo/bin/www
install dependencies:
$ cd nodejs-demo && npm install
run the app:
$ DEBUG=nodejs-demo ./bin/www
E:\project>
根據提示下載依賴包:
E:\project> cd .\nodejs-demo
E:\project\nodejs-demo> npm install
npm WARN deprecated [email protected]: use serve-favicon module
[email protected] node_modules\static-favicon
[email protected] node_modules\debug
[email protected] node_modules\ejs
[email protected] node_modules\cookie-parser
├── [email protected]
└── [email protected]
[email protected] node_modules\morgan
└── [email protected]
[email protected] node_modules\body-parser
├── [email protected]
├── [email protected] ([email protected], [email protected])
└── [email protected] ([email protected])
[email protected] node_modules\express
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected] ([email protected], [email protected])
├── [email protected] ([email protected], [email protected])
└── [email protected] ([email protected])
E:\project\nodejs-demo>
工程建立成功,啓動服務:
E:\project\nodejs-demo> npm start
> [email protected] start E:\project\nodejs-demo
> node ./bin/www
本地3000端口被打開,在瀏覽器地址欄輸入localhost:3000,訪問成功。
2、目錄結構
bin??存放命令行程序。 node_modules??存放所有的項目依賴庫。 public??存放靜態文件,包括css、js、img等。 routes??存放路由文件。 views??存放頁面文件(ejs模板)。 app.js??程序啓動文件。 package.json??項目依賴配置及開發者信息。E:\project\nodejs-demo> dir
目錄: E:\project\nodejs-demo
Mode LastWriteTime Length Name
---- ------------- ------ ----
d---- 2014/8/16 21:55 bin
d---- 2014/8/16 22:03 node_modules
d---- 2014/8/16 21:55 public
d---- 2014/8/16 21:55 routes
d---- 2014/8/16 21:55 views
-a--- 2014/8/16 21:55 1375 app.js
-a--- 2014/8/16 21:55 327 package.json
3、Express配置文件
打開app.js:
1 var express = require('express');
2 var path = require('path');
3 var favicon = require('static-favicon');
4 var logger = require('morgan');
5 var cookieParser = require('cookie-parser');
6 var bodyParser = require('body-parser');
7
8 var routes = require('./routes/index');
9 var users = require('./routes/users');
10
11 var app = express();
12
13 // view engine setup
14 app.set('views', path.join(__dirname, 'views'));
15 app.set('view engine', 'ejs');
16
17 app.use(favicon());
18 app.use(logger('dev'));
19 app.use(bodyParser.json());
20 app.use(bodyParser.urlencoded());
21 app.use(cookieParser());
22 app.use(express.static(path.join(__dirname, 'public')));
23
24 app.use('/', routes);
25 app.use('/users', users);
26
27 /// catch 404 and forward to error handler
28 app.use(function(req, res, next) {
29 var err = new Error('Not Found');
30 err.status = 404;
31 next(err);
32 });
33
34 /// error handlers
35
36 // development error handler
37 // will print stacktrace
38 if (app.get('env') === 'development') {
39 app.use(function(err, req, res, next) {
40 res.status(err.status || 500);
41 res.render('error', {
42 message: err.message,
43 error: err
44 });
45 });
46 }
47
48 // production error handler
49 // no stacktraces leaked to user
50 app.use(function(err, req, res, next) {
51 res.status(err.status || 500);
52 res.render('error', {
53 message: err.message,
54 error: {}
55 });
56 });
57
58
59 module.exports = app;
4、Ejs模板
修改app.js,讓ejs模板文件使用擴展名爲html的文件:
13 // view engine setup
14 app.set('views', path.join(__dirname, 'views'));
15 //app.set('view engine', 'ejs');
16 app.engine('html', require('ejs').renderFile);
17 app.set('view engine', 'html');
修改完成後,重命名views/index.ejs爲views/index.html。重啓服務,訪問成功。
5、安裝常用庫及頁面分離
添加bootstrap和jQuery:
E:\project\nodejs-demo> npm install bootstrap
[email protected] node_modules\bootstrap
E:\project\nodejs-demo> npm install jquery
[email protected] node_modules\jquery
E:\project\nodejs-demo>
接下來,把index.html分成三個部分:
header.html??頁面頭部區域。 index.html??頁面內容區域。 footer.html??頁面底部區域。header.html
1 <!DOCTYPE html>
2 <html lang="en">
3 <head>
4 <meta charset="utf-8">
5 <title><%= title %></title>
6 <!-- Bootstrap -->
7 <link href="/stylesheets/bootstrap.min.css" rel="stylesheet" media="screen">
8 </head>
9 <body screen_capture_injected="true">
index.html
1 <% include header.html %>
2 <h1><%= title %></h1>
3 <p>Welcome to <%= title %></p>
4 <% include footer.html %>
footer.html
1 <script src="/javascripts/jquery.min.js"></script>
2 <script src="/javascripts/bootstrap.min.js"></script>
3 </body>
4 </html>
重啓服務,訪問成功。
6、路由
登錄設計:
訪問路徑 | 頁面 | 描述 |
/ | index.html | 不需要登錄,可以直接訪問。 |
/home | home.html | 必須用戶登錄以後,纔可以訪問。 |
/login | login.html | 登錄頁面,用戶名密碼輸入正確,自動跳轉到home.html。 |
/logout | 無 | 退出登錄後,自動跳轉到index.html。 |
打開app.js文件,增加路由配置:
26 app.use('/', routes);
27 app.use('/users', users);
28 app.use('/login', routes);
29 app.use('/logout', routes);
30 app.use('/home', routes);
打開routes/index.js文件,添加對應方法:
1 var express = require('express');
2 var router = express.Router();
3
4 /* GET home page. */
5 router.get('/', function(req, res) {
6 res.render('index', { title: 'Express' });
7 });
8
9 router.route('/login')
10 .get(function(req, res) {
11 res.render('login', { title: '用戶登錄' });
12 })
13 .post(function(req, res) {
14 var user={
15 username: 'admin',
16 password: '123456'
17 }
18 if(req.body.username === user.username && req.body.password === user.password){
19 res.redirect('/home');
20 }
21 res.redirect('/login');
22 });
23
24 router.get('/logout', function(req, res) {
25 res.redirect('/');
26 });
27
28 router.get('/home', function(req, res) {
29 var user={
30 username:'admin',
31 password:'123456'
32 }
33 res.render('home', { title: 'Home', user: user });
34 });
35
36 module.exports = router;
創建views/login.html和views/home.html兩個文件:
login.html
1 <% include header.html %>
2 <div class="container">
3 <form class="col-sm-offset-4 col-sm-4 form-horizontal" role="form" method="post">
4 <fieldset>
5 <legend>用戶登錄</legend>
6 <div class="form-group">
7 <label class="col-sm-3 control-label" for="username">用戶名</label>
8 <div class="col-sm-9">
9 <input type="text" class="form-control" id="username" name="username" placeholder="用戶名" required>
10 </div>
11 </div>
12 <div class="form-group">
13 <label class="col-sm-3 control-label" for="password">密碼</label>
14 <div class="col-sm-9">
15 <input type="password" class="form-control" id="password" name="password" placeholder="密碼" required>
16 </div>
17 </div>
18 <div class="form-group">
19 <div class="col-sm-offset-3 col-sm-9">
20 <button type="submit" class="btn btn-primary">登錄</button>
21 </div>
22 </div>
23 </fieldset>
24 </form>
25 </div>
26 <% include footer.html %>
home.html
1 <% include header.html %>
2 <h1>Welcome <%= user.username %>, 歡迎登錄!!</h1>
3 <a class="btn" href="/logout">退出</a>
4 <% include footer.html %>
修改index.html,增加登錄鏈接:
1 <% include header.html %>
2 <h1>Welcome to <%= title %></h1>
3 <p><a href="/login">登錄</a></p>
4 <% include footer.html %>
路由及頁面已準備好,重啓服務,訪問成功。
7、session
安裝中間件express-session:
E:\project\nodejs-demo> npm install express-session
[email protected] node_modules\express-session
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected] ([email protected])
└── [email protected] ([email protected], [email protected])
E:\project\nodejs-demo>
安裝中間件connect-MongoDB:
E:\project\nodejs-demo> npm install connect-mongodb
\
> [email protected] install E:\project\nodejs-demo\node_modules\connect-mongodb\nod
e_modules\mongodb\node_modules\kerberos
> (node-gyp rebuild 2> builderror.log) || (exit 0)
|
E:\project\nodejs-demo\node_modules\connect-mongodb\node_modules\mongodb\node_mo
dules\kerberos>node "C:\Program Files\nodejs\node_modules\npm\bin\node-gyp-bin\\
..\..\node_modules\node-gyp\bin\node-gyp.js" rebuild
|
> [email protected] install E:\project\nodejs-demo\node_modules\connect-mongodb\node_m
odules\mongodb\node_modules\bson
> (node-gyp rebuild 2> builderror.log) || (exit 0)
E:\project\nodejs-demo\node_modules\connect-mongodb\node_modules\mongodb\node_mo
dules\bson>node "C:\Program Files\nodejs\node_modules\npm\bin\node-gyp-bin\\..\.
.\node_modules\node-gyp\bin\node-gyp.js" rebuild
[email protected] node_modules\connect-mongodb
├── [email protected] ([email protected], [email protected], [email protected])
└── [email protected] ([email protected], [email protected], [email protected])
E:\project\nodejs-demo>
安裝中間件mongodb:
E:\project\nodejs-demo> npm install mongodb
-
> [email protected] install E:\project\nodejs-demo\node_modules\mongodb\node_module
s\kerberos
> (node-gyp rebuild 2> builderror.log) || (exit 0)
-
E:\project\nodejs-demo\node_modules\mongodb\node_modules\kerberos>node "C:\Progr
am Files\nodejs\node_modules\npm\bin\node-gyp-bin\\..\..\node_modules\node-gyp\b
in\node-gyp.js" rebuild
|
> [email protected] install E:\project\nodejs-demo\node_modules\mongodb\node_modules\b
son
> (node-gyp rebuild 2> builderror.log) || (exit 0)
E:\project\nodejs-demo\node_modules\mongodb\node_modules\bson>node "C:\Program F
iles\nodejs\node_modules\npm\bin\node-gyp-bin\\..\..\node_modules\node-gyp\bin\n
ode-gyp.js" rebuild
[email protected] node_modules\mongodb
├── [email protected]
├── [email protected] ([email protected], [email protected], inheri
[email protected], [email protected])
└── [email protected] ([email protected])
E:\project\nodejs-demo>
添加database/settings.js和database/msession.js這兩個文件:
settings.js
1 module.exports = {
2 COOKIE_SECRET: 'ywang1724.com',
3 URL: 'mongodb://127.0.0.1:27017/nodedb',
4 DB: 'nodedb',
5 HOST: '127.0.0.1',
6 PORT: 27017,
7 USERNAME: 'admin',
8 PASSWORD: '123456'
9 };
msession.js
1 var Settings = require('./settings');
2 var Db = require('mongodb').Db;
3 var Server = require('mongodb').Server;
4 var db = new Db(Settings.DB, new Server(Settings.HOST, Settings.PORT, {auto_reconnect:true, native_parser: true}),{safe: false});
5
6 module.exports = db;
修改app.js文件:
1 var express = require('express');
2 var path = require('path');
3 var favicon = require('static-favicon');
4 var logger = require('morgan');
5 var cookieParser = require('cookie-parser');
6 var bodyParser = require('body-parser');
7
8 //採用connect-mongodb中間件作爲Session存儲
9 var session = require('express-session');
10 var Settings = require('./database/settings');
11 var MongoStore = require('connect-mongodb');
12 var db = require('./database/msession');
13
14 var routes = require('./routes/index');
15 var users = require('./routes/users');
16
17 var app = express();
18
19 // view engine setup
20 app.set('views', path.join(__dirname, 'views'));
21 //app.set('view engine', 'ejs');
22 app.engine('html', require('ejs').renderFile);
23 app.set('view engine', 'html');
24
25 app.use(favicon());
26 app.use(logger('dev'));
27 app.use(bodyParser.json());
28 app.use(bodyParser.urlencoded());
29 app.use(cookieParser());
30 //session配置
31 app.use(session({
32 cookie: { maxAge: 600000 },
33 secret: Settings.COOKIE_SECRET,
34 store: new MongoStore({
35 username: Settings.USERNAME,
36 password: Settings.PASSWORD,
37 url: Settings.URL,
38 db: db})
39 }))
40 app.use(function(req, res, next){
41 res.locals.user = req.session.user;
42 next();
43 });
44
45 app.use(express.static(path.join(__dirname, 'public')));
46
47 ......
修改index.js文件:
1 var express = require('express');
2 var router = express.Router();
3
4 /* GET home page. */
5 router.get('/', function(req, res) {
6 res.render('index', { title: 'Express' });
7 });
8
9 router.route('/login')
10 .get(function(req, res) {
11 res.render('login', { title: '用戶登錄' });
12 })
13 .post(function(req, res) {
14 var user = {
15 username: 'admin',
16 password: '123456'
17 }
18 if(req.body.username === user.username && req.body.password === user.password){
19 req.session.user = user;
20 res.redirect('/home');
21 } else {
22 res.redirect('/login');
23 }
24 });
25
26 router.get('/logout', function(req, res) {
27 req.session.user = null;
28 res.redirect('/');
29 });
30
31 router.get('/home', function(req, res) {
32 res.render('home', { title: 'Home' });
33 });
34
35 module.exports = router;
本地安裝數據庫MongoDB,新建用戶nodedb。重啓服務,訪問成功。
8、頁面訪問控制及提示
訪問控制設計:
訪問路徑 | 描述 |
/ | 任何人都可以訪問,不需要認證。 |
/home | 攔截get請求,調用authentication()進行認證,不通過則自動跳轉到登錄頁面。 |
/login | 任何人都可以訪問,不需要認證。 |
/logout | 任何人都可以訪問,不需要認證。 |
修改index.js文件:
34 router.get('/home', function(req, res) {
35 authentication(req, res);
36 res.render('home', { title: 'Home' });
37 });
38
39 function authentication(req, res) {
40 if (!req.session.user) {
41 return res.redirect('/login');
42 }
43 }
重啓服務,訪問成功。
添加頁面提示,修改app.js文件,增加res.locals.message:
40 app.use(function(req, res, next) {
41 res.locals.user = req.session.user;
42 var err = req.session.error;
43 delete req.session.error;
44 res.locals.message = '';
45 if (err) {
46 res.locals.message = '<div class="alert alert-warning">' + err + '</div>';
47 }
48 next();
49 });
修改index.js文件,增加req.session.error:
1 var express = require('express');
2 var router = express.Router();
3
4 /* GET home page. */
5 router.get('/', function(req, res) {
6 res.render('index', { title: 'Express' });
7 });
8
9 router.route('/login')
10 .get(function(req, res) {
11 if (req.session.user) {
12 res.redirect('/home');
13 }
14 res.render('login', { title: '用戶登錄' });
15 })
16 .post(function(req, res) {
17 var user = {
18 username: 'admin',
19 password: '123456'
20 }
21 if (req.body.username === user.username && req.body.password === user.password) {
22 req.session.user = user;
23 res.redirect('/home');
24 } else {
25 req.session.error='用戶名或密碼不正確';
26 res.redirect('/login');
27 }
28 });
29
30 router.get('/logout', function(req, res) {
31 req.session.user = null;
32 res.redirect('/');
33 });
34
35 router.get('/home', function(req, res) {
36 authentication(req, res);
37 res.render('home', { title: 'Home' });
38 });
39
40 function authentication(req, res) {
41 if (!req.session.user) {
42 req.session.error='請先登錄';
43 return res.redirect('/login');
44 }
45 }
46
47 module.exports = router;
修改login.html,增加<%- message %>:
5 <legend>用戶登錄</legend>
6 <%- message %>
7 <div class="form-group">
重啓服務,訪問成功。輸入錯誤用戶名密碼: