Nodejs Express4.x开发框架随手笔记


Posted in NodeJs onNovember 23, 2015

Express: ?web application framework for?Node.js?Express 是一个简洁、灵活的 node.js Web 应用开发框架, 它提供一系列强大的特性,帮助你创建各种 Web 和移动设备应用。

目录

此文重点介绍Express4.x(具体是4.10.4)的开发框架,其中还会涉及到Mongoose,Ejs,Bootstrap等相关内容。

建立工程
目录结构
Express4.x配置文件
Ejs模板使用
Bootstrap界面框架
路由功能
Session使用
页面提示
页面访问控制

开发环境:

Ubuntu

MonogoDB: v2.6.4

nodejs:v0.11.2

npm 2.1.10 ( 如果nodejs安装的时候是1.2.19版本,本文升级到了2.x版本)

1. 建立工程

进入工程目录

mkdir workplace

cd workplace

全局安装express,express作为命令被安装到了系统中.

npm install -g express

查看express版本

express -V

注意:在express4.x版本中已经不含有express命令了。

需要安装 express-generator

npm install express-generator -g

详细安装过程见:《准备Nodejs开发环境Ubuntu》

使用express命令创建工程,并支持ejs

hadoop@sven:~/workspace/nodeJs$ 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/images
create : nodejs-demo/public/javascripts
create : nodejs-demo/public/stylesheets
create : nodejs-demo/public/stylesheets/style.css
create : nodejs-demo/routes (路由目录,以后在这个目录下开发程序,然后在app.js里use)
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 (启动文件,用于启动app.js)
install dependencies:
$ cd nodejs-demo && npm install
run the app:
$ DEBUG=nodejs-demo ./bin/www

项目创建成功。

根据上述提示安装依赖:

cd nodejs-demo && npm install

根据提示启动web:

 $ DEBUG=nodejs-demo ./bin/www

不过我们这里不打算使用该方法启动程序。原因是我们在开发过程中需要使用nodemon这么一个工具。
nodemon用于动态识别开发过程中项目的改变,然后动态加载(这是Eclipse种开发java web类似)。该工具是开发web的必备啊

安装nodemon:

npm install nodemon -g

那么为什么我们上面不使用./bin/www脚本呢?

原因是nodemon ./bin/www 这样是没有办法识别项目的改动。(我个人实验的,如有知道的大牛,望赐教)

修改app.js:

把最有一行//module.exports = app;注释掉

换成:app.listen(3000);

使用下面命令启动app.js主程序:

hadoop@sven:~/workspace/nodeJs/nodejs-demo$ nodemon app.js

然后修改程序,看看是否会动态加载。会有下面提示:

1 Dec 16:22:07 ? [nodemon] restarting due to changes…
1 Dec 16:22:07 ? [nodemon] starting `node app.js`

表示生效。

测试:

本地的3000端口被打开,通过浏览器访问: localhost:3000

2. 目录结构

./
drwxrwxr-x 5 hadoop hadoop 4096 12月 1 15:57 ../
-rw-rw-r? 1 hadoop hadoop 1495 12月 1 16:22 app.js
-rw-r?r? 1 hadoop hadoop 12288 12月 1 16:22 .app.js.swp
drwxr-xr-x 2 hadoop hadoop 4096 12月 1 15:57 bin/
drwxrwxr-x 9 hadoop hadoop 4096 12月 1 15:58 node_modules/
-rw-rw-r? 1 hadoop hadoop 326 12月 1 15:57 package.json
drwxr-xr-x 5 hadoop hadoop 4096 12月 1 15:57 public/
drwxr-xr-x 2 hadoop hadoop 4096 12月 1 15:57 routes/
drwxr-xr-x 2 hadoop hadoop 4096 12月 1 15:57 views/

目录介绍:

node_modules, 存放所有的项目依赖库。(每个项目管理自己的依赖,与Maven,Gradle等不同)
package.json,项目依赖配置及开发者信息
app.js,程序主入口
public,静态文件(css,js,img)
routes,路由文件(MVC中的C,controller)
Views,页面文件(Ejs模板)
nodejs-demo/bin/www (启动文件,用于启动app.js)

打开app.js查看内容:

/**
* 模块依赖
*/
var express = require('express')
, routes = require('./routes')
, user = require('./routes/user')
, http = require('http')
, path = require('path');
var app = express();
//环境变量
app.set('port', process.env.PORT || 3000);
app.set('views', __dirname + '/views');
app.set('view engine', 'ejs');
app.use(express.favicon());
app.use(express.logger('dev'));
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(app.router);
app.use(express.static(path.join(__dirname, 'public')));
// 开发模式
if ('development' == app.get('env')) {
app.use(express.errorHandler());
}
// 路径解析
app.get('/', routes.index);
app.get('/users', user.list);
// 启动及端口
http.createServer(app).listen(app.get('port'), function(){
console.log('Express server listening on port ' + app.get('port'));
});

4. Ejs模板使用

让ejs模板文件,使用扩展名为html的文件。

修改:app.js

var ejs = require('ejs'); //引入ejs。重新安装依赖>
app.engine('.html', ejs.__express);
app.set('view engine', 'html');  // app.set('view engine', 'ejs');
重命名:views/*.ejs 为 views/*.html

访问localhost:3000正确

主要要重命名index.ejs等文件

5. 增加Bootstrap界面框架

其实就是把js,css文件复制到项目中对应该的目录里。 包括4个文件:

复制到public/stylesheets目录

bootstrap.min.css
bootstrap-responsive.min.css

复制到public/javascripts目录

bootstrap.min.js
jquery-1.9.1.min.js

接下来,我们把index.html页面切分成3个部分:header.html, index.html, footer.html

header.html, 为html页面的头部区域
index.html, 为内容显示区域
footer.html,为页面底部区域

header.html

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title><%=: title %></title>
<!-- Bootstrap -->
<link href="http://www.geedoo.info/stylesheets/bootstrap.min.css" rel="stylesheet" media="screen">
<!-- <link href="http://www.geedoo.info/css/bootstrap-responsive.min.css" rel="stylesheet" media="screen"> -->
</head>
<body screen_capture_injected="true">
index.html
<% include header.html %>
<h1><%= title %></h1>
<p>Welcome to <%= title %></p>
<% include footer.html %>
footer.html
<script src="http://www.geedoo.info/javascripts/jquery-1.9.1.min.js"></script>
<script src="http://www.geedoo.info/javascripts/bootstrap.min.js"></script>
</body>
</html>

访问localhost:3000正确。

我们已经成功的使用了EJS模板的功能,把公共的头部和底部从页面中分离出来了。

并已经引入了bootstrap界面框架。

6. 路由功能

我们设计一下用户登陆业务需求。

访问路径:/,页面:index.html,不需要登陆,可以直接访问。
访问路径:/home,页面:home.html,必须用户登陆后,才可以访问。
访问路径:/login,页面:login.html,登陆页面,用户名密码输入正确,自动跳转到home.html
访问路径:/logout,页面:无,退出登陆后,自动回到index.html页面

打开app.js文件,在增加路由配置

app.get('/',routes.index);
app.route('/login')
.get(routes.login)
post(routes.doLogin);
app.get('/logout',routes.logout);
app.get('/home',routes.home);

注:get为get请求,post为post请求,all为所有针对这个路径的请求

我们打开routes/index.js文件,增加对应的方法。

exports.index=function(req, res) {
 res.render('index', { title: 'index' });
};
exports.login=function(req,res){
 res.render('login',{title: '用户登录'});
};
exports.doLogin=function(req,res){
 var user = {
 username:"admin",
 password:"admin"
}
if(req.body.username==user.username && req.body.password==user.password){
 res.redirect('/home');
}
res.redirect('/login');
};
exports.logout = function(req,res){
 res.redirect('/');
};
exports.home = function(req,res){
 var user = {
 username:'admin',
 password:'admin'
 }
 res.render('home',{title:'Home',user:user});
};

创建views/login.html和views/home.html两个文件

login.html

<% include header.html %> 
<div class="container-fluid">
<form class="form-horizontal" method="post">
<fieldset>
<legend>用户登陆</legend>
<div class="control-group">
<label class="control-label" for="username">用户名</label>
<div class="controls">
<input type="text" class="input-xlarge" id="username" name="username">
</div>
</div>
<div class="control-group">
<label class="control-label" for="password">密码</label>
<div class="controls">
<input type="password" class="input-xlarge" id="password" name="password">
</div>
</div>
<div class="form-actions">
<button type="submit" class="btn btn-primary">登陆</button>
</div>
</fieldset>
</form>
</div>
<% include footer.html %>
home.html:
<% include header.html %>
<h1>Welcome <%= user.username %>, 欢迎登陆!!</h1>
<a claa="btn" href="http://www.geedoo.info/logout">退出</a>
<% include footer.html %>

修改index.html,增加登陆链接

index.html

<% include header.html %>
<h1>Welcome to <%= title %></h1>
<p><a href="http://www.geedoo.info/login">登陆</a></p>
<% include footer.html %>

路由及页面我们都写好了,快去网站上试试吧。

7. Session使用

从刚来的例子上面看,执行exports.doLogin时,如果用户名和密码正确,我们使用redirect方法跳转到的home

res.redirect('/home');

执行exports.home时,我们又用render渲染页面,并把user对象传给home.html页面

res.render('home', { title: 'Home',user: user});

为什么不能在doLogin时,就把user对象赋值给session,每个页面就不再传值了。

session这个问题,其实是涉及到服务器的底层处理方式。

像Java的web服务器,是多线程调用模型。每用户请求会打开一个线程,每个线程在内容中维护着用户的状态。

像PHP的web服务器,是交行CGI的程序处理,CGI是无状态的,所以一般用cookie在客户的浏览器是维护用户的状态。但cookie在客户端维护的信息是不够的,所以CGI应用要模仿用户session,就需要在服务器端生成一个session文件存储起来,让原本无状态的CGI应用,通过中间文件的方式,达到session的效果。

Nodejs的web服务器,也是CGI的程序无状态的,与PHP不同的地方在于,单线程应用,所有请求都是异步响应,通过callback方式返回数据。如果我们想保存session数据,也是需要找到一个存储,通过文件存储,redis,Mongdb都可以。

接下来,我将演示如何通过mongodb来保存session,并实现登陆后用户对象传递。

app.js文件

在相应位置添加下面代码:

var session = require('express-session');
var connect = require('connect');
var SessionStore = require("session-mongoose")(connect);
var store = new SessionStore({
url:"mongodb://localhost/session",
 interval: 120000
});
app.use(session({
 secret: 'test.com',
 store: store,
 cookie:{maxAge:10000} //expire session in 10 seconds
}));
//用于把登录用户设置到res.locals里面,在home.html里显示
app.use(function(req,res,next){
 res.locals.user = req.session.user;
 console.log('Session is = ',req.session.user);
 next();
});

需要添加中间件connect、session-mongoose。

其中session-mongoose是用于连接mongodb数据库。然后自动写入session信息到数据库中(也可以用mongoose中间件,但是要自己实现session的写入)

app.use(session(….)) 这里是全局设置了session的信息及session信息存储的方式。

注:app.js文件有顺序要求,一定要注意!!!

安装session-mongoose依赖库

npm install connect

npm install session-mongoose

npm install session-mongoose

安装有错误但是没关系。

访问:http://localhost:3000/login,正常

修改routes/index.js文件

exports.doLogin方法

exports.doLogin = function(req, res){
 var user={ username:'admin', password:'admin' } 
 if(req.body.username===user.username && req.body.password===user.password){ 
  req.session.user=user; 
  return res.redirect('/home');
 } else { 
  return res.redirect('/login'); 
 }
};

exports.logout方法

exports.logout = function(req, res){
 req.session.user=null;
 res.redirect('/');
};

exports.home方法

exports.home = function(req, res){
 res.render('home', { title: 'Home'});
};

这个时候session已经起作用了,exports.home的user显示传值已经被去掉了。 是通过app.js中app.use的res.locals变量,通过框架进行的赋值。

app.use(function(req, res, next){
 res.locals.user = req.session.user;
 next();
});

注:这个session是express4.10.4的写法,与express4之前的版本是不一样的。

访问页面可以查看mongodb有没有数据:

Nodejs Express4.x开发框架随手笔记

nodejs-mongodb
nodejs-mongodb

由于上面配置的 cookie:{maxAge:10000} //expire session in 10 seconds
过期时间,因此你会看到mongodb里面的数据过一段时间就被清除了。
参考:

Mongoose:http://mongoosejs.com/

关于express4.2.0与express3.x操作的区别:http://blog.csdn.net/u013758116/article/details/38758351

8. 页面提示

登陆的大体我们都已经讲完了,最后看一下登陆失败的情况。

我们希望如果用户登陆时,用户名或者密码出错了,会给用户提示,应该如何去实现。

打开app.js的,增加res.locals.message

登陆的大体我们都已经讲完了,最后看一下登陆失败的情况。

我们希望如果用户登陆时,用户名或者密码出错了,会给用户提示,应该如何去实现。

打开app.js的,增加res.locals.message

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-danger">' + err + '</div>';
 next();
});

修改login.html页面,<%- message %>

<% include header.html %>
<div class="container-fluid">
<form class="form-horizontal" method="post">
<fieldset>
<legend>用户登陆</legend>
<%- message %>
<div class="control-group">
<label class="control-label" for="username">用户名</label>
<div class="controls">
<input type="text" class="input-xlarge" id="username" name="username" value="admin">
</div>
</div>
<div class="control-group">
<label class="control-label" for="password">密码</label>
<div class="controls">
<input type="password" class="input-xlarge" id="password" name="password" value="admin">
</div>
</div>
<div class="form-actions">
<button type="submit" class="btn btn-primary">登陆</button>
</div>
</fieldset>
</form>
</div>
<% include footer.html %>

修改routes/index.js,增加req.session.error

exports.doLogin = function(req, res){
 var user={
 username:'admin',
 password:'admin'
 }
 if(req.body.username===user.username && req.body.password===user.password){
 req.session.user=user;
 return res.redirect('/home');
 } else {
 req.session.error='用户名或密码不正确';
 return res.redirect('/login');
 }
};

让我们来看看效果: http://localhost:3000/login 输入错误的和密码, 用户名:dad,密码:da

boostrap-nodejs

Nodejs Express4.x开发框架随手笔记

9. 页面访问控制

网站登陆部分按照我们的求已经完成了,但网站并不安全。

localhost:3000/home,页面本来是登陆以后才访问的,现在我们不要登陆,直接在浏览器输入也可访问。

页面报错了,提示<%= user.username %> 变量出错。

GET /home?user==a 500 15ms
TypeError: D:\workspace\project\nodejs-demo\views\home.html:2
1| <% include header.html %>
>> 2| <h1>Welcome <%= user.username %>, 欢迎登陆!!</h1>
3| <a claa="btn" href="http://www.geedoo.info/logout">退出</a>
4| <% include header.html %>
Cannot read property 'username' of null
at eval (eval at <anonymous> (D:\workspace\project\nodejs-demo\node_modules\ejs\lib\ejs.js:
at eval (eval at <anonymous> (D:\workspace\project\nodejs-demo\node_modules\ejs\lib\ejs.js:
at D:\workspace\project\nodejs-demo\node_modules\ejs\lib\ejs.js:249:15
at Object.exports.render (D:\workspace\project\nodejs-demo\node_modules\ejs\lib\ejs.js:287:
at View.exports.renderFile [as engine] (D:\workspace\project\nodejs-demo\node_modules\ejs\l
at View.render (D:\workspace\project\nodejs-demo\node_modules\express\lib\view.js:75:8)
at Function.app.render (D:\workspace\project\nodejs-demo\node_modules\express\lib\applicati
at ServerResponse.res.render (D:\workspace\project\nodejs-demo\node_modules\express\lib\res
at exports.home (D:\workspace\project\nodejs-demo\routes\index.js:36:8)
at callbacks (D:\workspace\project\nodejs-demo\node_modules\express\lib\router\index.js:161

这个页面被打开发,因为没有user.username参数。我们避免这样的错误发生。

还记录路由部分里说的get,post,all的作用吗?我现在要回到路由配置中,再做点事情。

修改app.js文件

app.get('/',routes.index);
app.route('/login')
.all(notAuthentication)
.get(routes.login)
.post(routes.doLogin);
app.route('/logout')
app.get('/',routes.index);
app.route('/login')
.all(notAuthentication)
.get(routes.login)
.post(routes.doLogin);
app.route('/logout')
.get(authentication)
.get(routes.logout);
app.route('/home')
.get(authentication)
.get(routes.home);

访问控制:

/ ,谁访问都行,没有任何控制
/login,用all拦截所有访问/login的请求,先调用authentication,用户登陆检查
/logout,用get拦截访问/login的请求,先调用notAuthentication,用户不登陆检查
/home,用get拦截访问/home的请求,先调用Authentication,用户登陆检查
修改app.js文件,增加authentication,notAuthentication两个方法

function authentication(req, res, next) {
 if (!req.session.user) {
 req.session.error='请先登陆';
 return res.redirect('/login');
 }
 next();
}
function notAuthentication(req, res, next) {
 if (req.session.user) {
  req.session.error='已登陆';
  return res.redirect('/home');
 }
 next();
}

配置好后,我们未登陆,直接访问localhost:3000/home时或者localhost:3000/logout,就会跳到/login页面

登录后, 访问localhost:3000/login 则直接跳到/home页面

到此,express4 相关内容到此为止。

以上内容是小编给大家分享的Nodejs Express4.x开发框架随手笔记,希望大家喜欢。

NodeJs 相关文章推荐
Nodejs进程管理模块forever详解
Jun 01 NodeJs
使用upstart把nodejs应用封装为系统服务实例
Jun 01 NodeJs
nodejs教程之制作一个简单的文章发布系统
Nov 21 NodeJs
nodeJS代码实现计算交社保是否合适
Mar 09 NodeJs
NodeJS远程代码执行
Aug 28 NodeJs
详解nodejs 文本操作模块-fs模块(四)
Dec 22 NodeJs
详解Windows下安装Nodejs步骤
May 18 NodeJs
nodejs简单访问及操作mysql数据库的方法示例
Mar 15 NodeJs
nodejs基于express实现文件上传的方法
Mar 19 NodeJs
nodejs 简单实现动态html的方法
May 12 NodeJs
NodeJs项目中关闭ESLint的方法
Aug 09 NodeJs
关于NodeJS中的循环引用详解
Jul 23 NodeJs
Nodejs的express使用教程
Nov 23 #NodeJs
nodejs初步体验篇
Nov 23 #NodeJs
Nodejs初级阶段之express
Nov 23 #NodeJs
基于html5和nodejs相结合实现websocket即使通讯
Nov 19 #NodeJs
浅析nodejs实现Websocket的数据接收与发送
Nov 19 #NodeJs
Nodejs实战心得之eventproxy模块控制并发
Oct 27 #NodeJs
浅谈Nodejs观察者模式
Oct 13 #NodeJs
You might like
PHP 开源框架22个简单简介
2009/08/24 PHP
php中CI操作多个数据库的代码
2012/07/05 PHP
php获取系统变量方法小结
2015/05/29 PHP
PHP判断是否连接上网络的方法
2015/07/01 PHP
php抽奖概率算法(刮刮卡,大转盘)
2020/04/17 PHP
php根据年月获取当月天数及日期数组的方法
2016/11/30 PHP
在云虚拟主机部署thinkphp5项目的步骤详解
2017/12/21 PHP
jquery操作select option 的代码小结
2011/06/21 Javascript
ExtJS下 Ext.Direct加载和提交过程排错小结
2013/04/02 Javascript
购物车选中得到价格实现示例
2014/01/26 Javascript
jquery仿搜索自动联想功能代码
2014/05/23 Javascript
js中对函数设置默认参数值的3种方法
2015/10/23 Javascript
微信小程序中添加客服按钮contact-button功能
2018/04/27 Javascript
使用JS实现导航切换时高亮显示的示例讲解
2018/08/22 Javascript
[07:49]2014DOTA2国际邀请赛 Newbee夺冠后采访xiao8坦言奖金会上交
2014/07/23 DOTA
[00:43]DOTA2小紫本全民票选福利PA至宝全方位展示
2014/11/25 DOTA
python的描述符(descriptor)、装饰器(property)造成的一个无限递归问题分享
2014/07/09 Python
解密Python中的描述符(descriptor)
2015/06/03 Python
python开发之字符串string操作方法实例详解
2015/11/12 Python
使用简单工厂模式来进行Python的设计模式编程
2016/03/01 Python
python 上下文管理器使用方法小结
2017/10/10 Python
使用Python来开发微信功能
2018/06/13 Python
对python读取CT医学图像的实例详解
2019/01/24 Python
python实现图书借阅系统
2019/02/20 Python
详解Python的循环结构知识点
2019/05/20 Python
Pytorch之保存读取模型实例
2019/12/30 Python
详解Python调用系统命令的六种方法
2021/01/28 Python
浅谈CSS3中的变形功能-transform功能
2017/12/27 HTML / CSS
video结合canvas实现视频在线截图功能
2018/06/25 HTML / CSS
巴塞罗那观光通票:Barcelona Pass
2019/10/30 全球购物
2015年中职班主任工作总结
2015/05/25 职场文书
幼儿园保教工作总结2015
2015/10/15 职场文书
创业计划书之熟食店
2019/10/16 职场文书
JS如何使用剪贴板操作Clipboard API
2021/05/17 Javascript
关于MySQL中的 like操作符详情
2021/11/17 MySQL
解决MySQL添加新用户-ERROR 1045 (28000)的问题
2022/03/03 MySQL