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.3
12
E:\project> node -v
v0.
10.30
E:\project> npm -v
1.4
.
21
E:\project> express -V
4.2
.
0
1、建立工程
使用express命令建立工程,并支持ejs:
根据提示下载依赖包:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
E:\project>
cd
.\nodejs-demo
E:\project\nodejs-demo> npm
install
npm WARN deprecated static-favicon@1.0.2: use serve-favicon module
static-favicon@1.0.2 node_modules\static-favicon
debug@0.7.4 node_modules\debug
ejs@0.8.8 node_modules\ejs
cookie-parser@1.0.1 node_modules\cookie-parser
├── cookie-signature@1.0.3 └── cookie@0.1.0 morgan@1.0.1 node_modules\morgan
└── bytes@0.3.0 body-parser@1.0.2 node_modules\body-parser
├── qs@0.6.6 ├── raw-body@1.1.7 (bytes@1.0.0, string_decoder@0.10.25-1)
└──
type
-is@1.1.0 (mime@1.2.11)
express@4.2.0 node_modules\express
├── parseurl@1.0.1 ├── utils-merge@1.0.0 ├── cookie@0.1.2 ├── merge-descriptors@0.0.2 ├── escape-html@1.0.1 ├── range-parser@1.0.0 ├── fresh@0.2.2 ├── cookie-signature@1.0.3 ├── debug@0.8.1 ├── methods@1.0.0 ├── buffer-crc32@0.2.1 ├── serve-static@1.1.0 ├── path-to-regexp@0.1.2 ├── qs@0.6.6 ├── send@0.3.0 (debug@0.8.0, mime@1.2.11)
├── accepts@1.0.1 (negotiator@0.4.7, mime@1.2.11)
└──
type
-is@1.1.0 (mime@1.2.11)
E:\project\nodejs-demo>
|
工程建立成功,启动服务:
1
|
E:\project\nodejs-demo> npm start > nodejs-demo@0.0.1 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——项目依赖配置及开发者信息。
1
2
3
4
5
6
7
8
9
10
11
|
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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
|
var
express = require(
'express'
);
var
path = require(
'path'
);
var
favicon = require(
'static-favicon'
);
var
logger = require(
'morgan'
);
var
cookieParser = require(
'cookie-parser'
);
var
bodyParser = require(
'body-parser'
);
var
routes = 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'
);
app.use(favicon());
app.use(logger(
'dev'
));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded());
app.use(cookieParser());
app.use(express.
static
(path.join(__dirname,
'public'
)));
app.use(
'/'
, routes);
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 handlers
// development error handler
// will print stacktrace
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
});
});
}
// production error handler
// no stacktraces leaked to user
app.use(
function
(err, req, res, next) {
res.status(err.status || 500);
res.render(
'error'
, {
message: err.message,
error: {}
});
});
module.exports = app;
|
4、Ejs模板
修改app.js,让ejs模板文件使用扩展名为html的文件:
1
2
3
4
5
|
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 bootstrap@3.2.0 node_modules\bootstrap E:\project\nodejs-demo> npm install jquery jquery@2.1.1 node_modules\jquery E:\project\nodejs-demo>
接下来,把index.html分成三个部分:
- header.html——页面头部区域。
- index.html——页面内容区域。
- footer.html——页面底部区域。
header.html
1
2
3
4
5
6
7
8
9
|
<!
DOCTYPE
html>
<
html
lang
=
"en"
>
<
head
>
<
meta
charset
=
"utf-8"
>
<
title
><%= title %></
title
>
<!-- Bootstrap -->
<
link
href
=
"/stylesheets/bootstrap.min.css"
rel
=
"stylesheet"
media
=
"screen"
>
</
head
>
<
body
screen_capture_injected
=
"true"
>
|
index.html
1
2
3
4
|
1 <% include header.html %>
2 <
h1
><%= title %></
h1
>
3 <
p
>Welcome to <%= title %></
p
>
4 <% include footer.html %>
|
1
2
3
4
5
6
|
<script src=
"/javascripts/jquery.min.js"
></script>
<script src=
"/javascripts/bootstrap.min.js"
></script>
</body>
</html>
|
重启服务,访问成功。
6、路由
登录设计:
访问路径 | 页面 | 描述 |
/ | index.html | 不需要登录,可以直接访问。 |
/home | home.html | 必须用户登录以后,才可以访问。 |
/login | login.html | 登录页面,用户名密码输入正确,自动跳转到home.html。 |
/logout | 无 | 退出登录后,自动跳转到index.html。 |
打开app.js文件,增加路由配置:
1
2
3
4
5
|
26 app.use(
'/'
, routes);
27 app.use(
'/users'
, users);
28 app.use(
'/login'
, routes);
29 app.use(
'/logout'
, routes);
30 app.use(
'/home'
, routes);
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
|
var
express = require(
'express'
);
var
router = express.Router();
/* GET home page. */
router.get(
'/'
,
function
(req, res) {
res.render(
'index'
, { title:
'Express'
});
});
router.route(
'/login'
)
.get(
function
(req, res) {
res.render(
'login'
, { title:
'用户登录'
});
})
.post(
function
(req, res) {
var
user={
username:
'admin'
,
password:
'123456'
}
if
(req.body.username === user.username && req.body.password === user.password){
res.redirect(
'/home'
);
}
res.redirect(
'/login'
);
});
router.get(
'/logout'
,
function
(req, res) {
res.redirect(
'/'
);
});
router.get(
'/home'
,
function
(req, res) {
var
user={
username:
'admin'
,
password:
'123456'
}
res.render(
'home'
, { title:
'Home'
, user: user });
});
module.exports = router;
|
创建views/login.html和views/home.html两个文件:
login.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
<% include header.html %>
<
div
class
=
"container"
>
<
form
class
=
"col-sm-offset-4 col-sm-4 form-horizontal"
role
=
"form"
method
=
"post"
>
<
fieldset
>
<
legend
>用户登录</
legend
>
<
div
class
=
"form-group"
>
<
label
class
=
"col-sm-3 control-label"
for
=
"username"
>用户名</
label
>
<
div
class
=
"col-sm-9"
>
<
input
type
=
"text"
class
=
"form-control"
id
=
"username"
name
=
"username"
placeholder
=
"用户名"
required>
</
div
>
</
div
>
<
div
class
=
"form-group"
>
<
label
class
=
"col-sm-3 control-label"
for
=
"password"
>密码</
label
>
<
div
class
=
"col-sm-9"
>
<
input
type
=
"password"
class
=
"form-control"
id
=
"password"
name
=
"password"
placeholder
=
"密码"
required>
</
div
>
</
div
>
<
div
class
=
"form-group"
>
<
div
class
=
"col-sm-offset-3 col-sm-9"
>
<
button
type
=
"submit"
class
=
"btn btn-primary"
>登录</
button
>
</
div
>
</
div
>
</
fieldset
>
</
form
>
</
div
>
<% include footer.html %>
|
home.html
1
2
3
4
|
1 <% include header.html %>
2 <h1>Welcome <%= user.username %>, 欢迎登录!!</h1>
3 <a
class
=
"btn"
href=
"/logout"
>退出</a>
4 <% include footer.html %>
|
修改index.html,增加登录链接:
1
2
3
4
|
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:
1
2
3
4
5
|
E:\project\nodejs-demo> npm install express-session
express-session@1.7.5 node_modules\express-session
├── cookie@0.1.2 ├── cookie-signature@1.0.4 ├── on-headers@1.0.0 ├── utils-merge@1.0.0 ├── parseurl@1.3.0 ├── buffer-crc32@0.2.3 ├── depd@0.4.4 ├── debug@1.0.4 (ms@0.6.2)
└── uid-safe@1.0.1 (base64-url@1.0.0, mz@1.0.0)
E:\project\nodejs-demo>
|
安装中间件connect-mongodb:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
E:\project\nodejs-demo> npm
install
connect-mongodb
\ > kerberos@0.0.3
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 |
> bson@0.2.11
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
connect-mongodb@1.1.5 node_modules\connect-mongodb
├── connect@1.9.2 (mime@1.2.11, formidable@1.0.15, qs@1.2.2)
└── mongodb@1.4.8 (kerberos@0.0.3, readable-stream@1.0.27-1, bson@0.2.11)
E:\project\nodejs-demo>
|
安装中间件mongodb:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
E:\project\nodejs-demo> npm
install
mongodb -
> kerberos@0.0.3
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 |
> bson@0.2.11
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
mongodb@1.4.8 node_modules\mongodb
├── kerberos@0.0.3 ├── readable-stream@1.0.27-1 (isarray@0.0.1, string_decoder@0.10.25-1, inheri
ts@2.0.1, core-util-is@1.0.1)
└── bson@0.2.11 (nan@1.2.0)
E:\project\nodejs-demo>
|
添加database/settings.js和database/msession.js这两个文件:
settings.js
1
2
3
4
5
6
7
8
9
|
module.exports = {
COOKIE_SECRET:
'ywang1724.com'
,
URL:
'mongodb://127.0.0.1:27017/nodedb'
,
DB:
'nodedb'
,
HOST:
'127.0.0.1'
,
PORT: 27017,
USERNAME:
'admin'
,
PASSWORD:
'123456'
};
|
msession.js
1
2
3
4
5
6
|
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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
|
var
express = require(
'express'
);
var
path = require(
'path'
);
var
favicon = require(
'static-favicon'
);
var
logger = require(
'morgan'
);
var
cookieParser = require(
'cookie-parser'
);
var
bodyParser = require(
'body-parser'
);
//采用connect-mongodb中间件作为Session存储
var
session = require(
'express-session'
);
var
Settings = require(
'./database/settings'
);
var
MongoStore = require(
'connect-mongodb'
);
var
db = require(
'./database/msession'
);
var
routes = 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');
app.engine(
'html'
, require(
'ejs'
).renderFile);
app.set(
'view engine'
,
'html'
);
app.use(favicon());
app.use(logger(
'dev'
));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded());
app.use(cookieParser());
//session配置
app.use(session({
cookie: { maxAge: 600000 },
secret: Settings.COOKIE_SECRET,
store:
new
MongoStore({
username: Settings.USERNAME,
password: Settings.PASSWORD,
url: Settings.URL,
db: db})
}))
app.use(
function
(req, res, next){
res.locals.user = req.session.user;
next();
});
app.use(express.
static
(path.join(__dirname,
'public'
)));
......
|
修改index.js文件:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
var
express = require(
'express'
);
var
router = express.Router();
/* GET home page. */
router.get(
'/'
,
function
(req, res) {
res.render(
'index'
, { title:
'Express'
});
});
router.route(
'/login'
)
.get(
function
(req, res) {
res.render(
'login'
, { title:
'用户登录'
});
})
.post(
function
(req, res) {
var
user = {
username:
'admin'
,
password:
'123456'
}
if
(req.body.username === user.username && req.body.password === user.password){
req.session.user = user;
res.redirect(
'/home'
);
}
else
{
res.redirect(
'/login'
);
}
});
router.get(
'/logout'
,
function
(req, res) {
req.session.user =
null
;
res.redirect(
'/'
);
});
router.get(
'/home'
,
function
(req, res) {
res.render(
'home'
, { title:
'Home'
});
});
module.exports = router;
|
本地安装数据库MongoDB,新建用户nodedb。重启服务,访问成功。
8、页面访问控制及提示
访问控制设计:
访问路径 | 描述 |
/ | 任何人都可以访问,不需要认证。 |
/home | 拦截get请求,调用authentication()进行认证,不通过则自动跳转到登录页面。 |
/login | 任何人都可以访问,不需要认证。 |
/logout | 任何人都可以访问,不需要认证。 |
修改index.js文件:
1
2
3
4
5
6
7
8
9
10
|
router.get(
'/home'
,
function
(req, res) {
authentication(req, res);
res.render(
'home'
, { title:
'Home'
});
});
function
authentication(req, res) {
if
(!req.session.user) {
return
res.redirect(
'/login'
);
}
}
|
重启服务,访问成功。
添加页面提示,修改app.js文件,增加res.locals.message:
1
2
3
4
5
6
7
8
9
10
|
app.use( function (req, res, next) {
res.locals.user = req.session.user;
var err = req.session.error;
delete req.session.error;
res.locals.message = '' ;
if (err) {
res.locals.message = '<div class="alert alert-warning">' + err + '</div>' ;
}
next();
});
|
修改index.js文件,增加req.session.error:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
|
var
express = require(
'express'
);
var
router = express.Router();
/* GET home page. */
router.get(
'/'
,
function
(req, res) {
res.render(
'index'
, { title:
'Express'
});
});
router.route(
'/login'
)
.get(
function
(req, res) {
if
(req.session.user) {
res.redirect(
'/home'
);
}
res.render(
'login'
, { title:
'用户登录'
});
})
.post(
function
(req, res) {
var
user = {
username:
'admin'
,
password:
'123456'
}
if
(req.body.username === user.username && req.body.password === user.password) {
req.session.user = user;
res.redirect(
'/home'
);
}
else
{
req.session.error= '用户名或密码不正确' ;
res.redirect( '/login' );
}
});
router.get(
'/logout'
,
function
(req, res) {
req.session.user =
null
;
res.redirect(
'/'
);
});
router.get(
'/home'
,
function
(req, res) {
authentication(req, res);
res.render(
'home'
, { title:
'Home'
});
});
function
authentication(req, res) {
if
(!req.session.user) {
req.session.error=
'请先登录'
;
return
res.redirect(
'/login'
);
}
}
module.exports = router;
|
修改login.html,增加<%- message %>:
1
2
3
|
5 <legend>用户登录</legend>
6 <%- message %>
7 <div
class
=
"form-group"
>
|
重启服务,访问成功。输入错误用户名密码: