Nodejs开发框架Express3.0开发手记–从零开始

前言

Nodejs给Javascript赋予了服务端应用的生命,Jquery让Javascript成为浏览中开发的利器。 最近学习了Nodejs的Express3.0的开发框架,本来是按照“node.js开发指南”书中介绍,但“node.js开发指南”讲的是Express2.x的,从Express2.x到Express3.0自己模索中还是走了不少弯路的。写篇文章总结一下。

关于作者

张丹(Conan), 程序员Java,R,PHP,Javacript
weibo:@Conan_Z
blog: http://blog.fens.me
email: bsspirit@gmail.com

转载请注明出处:
http://blog.fens.me/nodejs-express3/

程序代码已经上传到github有需要的同学,自行下载。
https://github.com/bsspirit/nodejs-demo

nodejs intro

从零开始nodejs系列文章

从零开始nodejs系列文章,将介绍如何利Javascript做为服务端脚本,通过Nodejs框架web开发。Nodejs框架是基于V8的引擎,是目前速度最快的Javascript引擎。chrome浏览器就基于V8,同时打开20-30个网页都很流畅。Nodejs标准的web开发框架Express,可以帮助我们迅速建立web站点,比起PHP的开发效率更高,而且学习曲线更低。非常适合小型网站,个性化网站,我们自己的Geek网站!!

目录

此文重点介绍Express3.0的开发框架,其中还会涉及到Mongoose,Ejs,Bootstrap等相关内容。
Express已经升级到4.x,请同时参考文章,Node.js开发框架Express4.x

  1. 建立工程
  2. 目录结构
  3. Express3.0配置文件
  4. Ejs模板使用
  5. Bootstrap界面框架
  6. 路由功能
  7. Session使用
  8. 页面提示
  9. 页面访问控制

开发环境:

Win7旗舰版 64bit

MonogoDB: v2.4.3


Tue May 14 09:24:50.118 [initandlisten] MongoDB starting : pid=1716 port=27017 dbpath=./data 64-bit host=PC201304202140
Tue May 14 09:24:50.119 [initandlisten] db version v2.4.3
Tue May 14 09:24:50.119 [initandlisten] git version: fe1743177a5ea03e91e0052fb5e2cb2945f6d95f
Tue May 14 09:24:50.119 [initandlisten] build info: windows sys.getwindowsversion(major=6, minor=1, build=7601, platform=2, service_pack='Service Pack 1') BOOST_LIB_VERSION=1_49
Tue May 14 09:24:50.119 [initandlisten] allocator: system
Tue May 14 09:24:50.119 [initandlisten] options: { dbpath: "./data" }
Tue May 14 09:24:50.188 [initandlisten] journal dir=./data\journal
Tue May 14 09:24:50.189 [initandlisten] recover : no journal files present, no recovery needed
Tue May 14 09:24:50.441 [initandlisten] preallocateIsFaster=true 3.26
Tue May 14 09:24:50.778 [initandlisten] preallocateIsFaster=true 5.88
Tue May 14 09:24:51.827 [initandlisten] waiting for connections on port 27017
Tue May 14 09:24:51.827 [websvr] admin web console waiting for connections on port 28017

nodejs: v0.10.5, npm 1.2.19

node -v
v0.10.5
npm -v
1.2.19

1. 建立工程

进入工程目录


cd D:\workspace\project

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


npm install -g express

查看express版本


express -V
3.2.2

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


D:\workspace\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/user.js
create : nodejs-demo/views
create : nodejs-demo/views/index.ejs

install dependencies:
$ cd nodejs-demo && npm install
run the app:
$ node app

根据提示,下载依赖包


cd nodejs-demo && npm install

express@3.2.2 node_modules\express
├── methods@0.0.1
├── fresh@0.1.0
├── buffer-crc32@0.2.1
├── range-parser@0.0.4
├── cookie-signature@1.0.1
├── cookie@0.0.5
├── qs@0.6.3
├── commander@0.6.1
├── debug@0.7.2
├── mkdirp@0.3.4
├── send@0.1.0 (mime@1.2.6)
└── connect@2.7.8 (pause@0.0.1, bytes@0.2.0, formidable@1.0.13)

模板项目建立成功,启动模板项目。


D:\workspace\project\nodejs-demo>node app.js
Express server listening on port 3000

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

通过node启动程序,每次代码修改都需要重新启动。 有一个工具supervisor,每次修改代码后会自动重启,会我们开发省很多的时间。


npm install supervisor

再启动服务


D:\workspace\project\nodejs-demo>supervisor app.js

DEBUG: Running node-supervisor with
DEBUG: program 'app.js'
DEBUG: --watch '.'
DEBUG: --ignore 'undefined'
DEBUG: --extensions 'node|js'
DEBUG: --exec 'node'

DEBUG: Starting child process with 'node app.js'
DEBUG: Watching directory 'D:\workspace\project\nodejs-demo' for changes.
Express server listening on port 3000

 

2. 目录结构

D:\workspace\project\nodejs-demo>dir

2013/05/14 09:42 877 app.js
2013/05/14 09:48 <DIR> node_modules
2013/05/14 09:42 184 package.json
2013/05/14 09:42 <DIR> public
2013/05/14 09:42 <DIR> routes
2013/05/14 09:42 <DIR> views

目录介绍:

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

3. Express3.0配置文件

打开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


app.engine('.html', ejs.__express);
app.set('view engine', 'html');// app.set('view engine', 'ejs');

修改后,ejs变量没有定义,supervisor的程序会一直报错


ReferenceError: ejs is not defined
at Object. (D:\workspace\project\nodejs-demo\app.js:17:21)
at Module._compile (module.js:456:26)
at Object.Module._extensions..js (module.js:474:10)
at Module.load (module.js:356:32)
at Function.Module._load (module.js:312:12)
at Function.Module.runMain (module.js:497:10)
at startup (node.js:119:16)
at node.js:901:3
DEBUG: Program node app.js exited with code 8

在app.js中增加ejs变量


var express = require('express')
, routes = require('./routes')
, user = require('./routes/user')
, http = require('http')
, path = require('path')
, ejs = require('ejs');

访问localhost:3000,程序报错


Error: Failed to lookup view "index"
at Function.app.render (D:\workspace\project\nodejs-demo\node_modules\express\lib\application.js:495:17)
at ServerResponse.res.render (D:\workspace\project\nodejs-demo\node_modules\express\lib\response.js:756:7)
at exports.index (D:\workspace\project\nodejs-demo\routes\index.js:7:7)
at callbacks (D:\workspace\project\nodejs-demo\node_modules\express\lib\router\index.js:161:37)
at param (D:\workspace\project\nodejs-demo\node_modules\express\lib\router\index.js:135:11)
at pass (D:\workspace\project\nodejs-demo\node_modules\express\lib\router\index.js:142:5)
at Router._dispatch (D:\workspace\project\nodejs-demo\node_modules\express\lib\router\index.js:170:5)
at Object.router (D:\workspace\project\nodejs-demo\node_modules\express\lib\router\index.js:33:10)
at next (D:\workspace\project\nodejs-demo\node_modules\express\node_modules\connect\lib\proto.js:190:15)
at Object.methodOverride [as handle] (D:\workspace\project\nodejs-demo\node_modules\express\node_modules\connect\lib\middleware\methodOverride.js:37:5)
GET / 500 26ms

重命名:views/indes.ejs 为 views/index.html

访问localhost:3000正确

 

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="/stylesheets/bootstrap.min.css" rel="stylesheet" media="screen">
<!-- <link href="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 %>

注:express3.0时,ejs嵌入其他页面时使用include,express2.x用法不一样。

footer.html


<script src="/javascripts/jquery-1.9.1.min.js"></script>
<script src="/javascripts/bootstrap.min.js"></script>
</body>
</html>

访问localhost:3000正确。

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

并已经引入了bootstrap界面框架,后面讲到“登陆界面”的时候,就会看到bootstrap界面效果了。

 

6. 路由功能

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

访问路径:/,页面:index.html,不需要登陆,可以直接访问。
访问路径:/home,页面:home.html,必须用户登陆后,才可以访问。
访问路径:/login,页面:login.html,登陆页面,用户名密码输入正确,自动跳转到home.html
访问路径:/logout,页面:无,退出登陆后,自动回到index.html页面
打开app.js文件,在增加路由配置


app.get('/', routes.index);
app.get('/login', routes.login);
app.post('/login', 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 %>

login
注:使用了bootstrap界面框架,效果还不错吧.

home.html


<% include header.html %>
<h1>Welcome <%= user.username %>, 欢迎登陆!!</h1>
<a claa="btn" href="/logout">退出</a>
<% include footer.html %>

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


<% include header.html %>
<h1>Welcome to <%= title %></h1>
<p><a href="/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 express = require('express')
, routes = require('./routes')
, user = require('./routes/user')
, http = require('http')
, path = require('path')
, ejs = require('ejs')
, SessionStore = require("session-mongoose")(express);
var store = new SessionStore({
url: "mongodb://localhost/session",
interval: 120000
});
....
app.use(express.favicon());
app.use(express.logger('dev'));
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(express.cookieParser());
app.use(express.cookieSession({secret : 'fens.me'}));
app.use(express.session({
secret : 'fens.me',
store: store,
cookie: { maxAge: 900000 }
}));
app.use(function(req, res, next){
res.locals.user = req.session.user;
next();
});
app.use(app.router);
app.use(express.static(path.join(__dirname, 'public')));

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

安装session-mongoose依赖库


D:\workspace\project\nodejs-demo>npm install session-mongoose
D:\workspace\project\nodejs-demo\node_modules\session-mongoose\node_modules\mongoose\node_modules\mongodb\node_modules\bson>node "D:\toolkit\nodejs\node_modules\npm\bin\node-gyp-bin\\..\..\node_modules\node-gyp\bin\node-gyp.js" rebuild
C:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\Microsoft.Cpp.InvalidPlatform.Targets(23,7): error MSB8007: 项目“kerberos.vcxproj”的平台无效。平台为“x64”。您会看到此消息的可能原因是,您尝试在没有解决方案文件的情况下生成项目,并且为
oose\node_modules\mongoose\node_modules\mongodb\node_modules\bson\build\bson.vcxproj]
session-mongoose@0.2.2 node_modules\session-mongoose
└── mongoose@3.6.10 (mpath@0.1.1, ms@0.1.0, hooks@0.2.1, sliced@0.0.3, muri@0.3.1, mpromise@0.2.1, mongodb@1.3.3)

安装有错误但是没关系。

访问: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是express3.0的写法,与express2.x是不一样的。原理是在框架内每次赋值,把我们刚才手动传值的过程,让框架去完成了。

 

8. 页面提示

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

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

打开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-error">' + 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 输入错误的和密码, 用户名:adminfe,密码:12121

loginErr

 

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="/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.all('/login', notAuthentication);
app.get('/login', routes.login);
app.post('/login', routes.doLogin);
app.get('/logout', authentication);
app.get('/logout', routes.logout);
app.get('/home', authentication);
app.get('/home', 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('/');
}
next();
}

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

loginHome

如果你也出现图片显示的内容,那么恭喜你了。

Nodejs使用Express3.0框架的第一步你已经完成了,并且还使用了ejs,bootstrap,mongoose库的使用。

希望此文对大家有所帮助。

Express已经升级到4.x,请同时参考文章,Node.js开发框架Express4.x

转载请注明出处:
http://blog.fens.me/nodejs-express3/

程序代码已经上传到github有需要的同学,自行下载。
https://github.com/bsspirit/nodejs-demo

打赏作者

This entry was posted in Javascript语言实践

0 0 votes
Article Rating
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

202 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments

[…] Nodejs开发框架Express3.0开发手记–从零开始 http://blog.fens.me/nodejs-express3/ […]

Evan

很尊敬认真写教程的人。。。今天回去就学习一下。

esteem

权限验证的事情 每个请求都配置2个拦截 很累啊 没有通配的吗?

youxiachai

如何自定义非路由路径的页面?

十七亮

app.get(‘/logout’, authentication);
app.get(‘/logout’, routes.logout);
我用这种配置两个路由的为什么不能加载呢,是不是express3.X不支持了?

十七亮

嗯,加上next()就可以了,多谢

十七亮

post路由无法修改session的值是哪里有问题,但是get路由就可以
用的 session-mongoose

十七亮

我用connect-mongo是可以的 用session-mongoose不行

Centre2

更正个错误:
==========
重命名:views/indes.ejs 为 views/indes.html (index <–)

访问localhost:3000正确

Centre2

Welcome to
(footer.html <–)

Conan Zhang

多谢提醒,已经修改了。

dym

博主,请教一个问题,我跟着第7步做的时候,安装session-mongoose时,运行app.js之后,出现下面的问题,求解

Conan Zhang

你不是本机没有安装 mongodb?
localhost:27017,是mongodb的默认使用端口,无法访问。

dym

嗯,是没装mongodb,我太白痴了。谢谢博主的提醒。

Conan Zhang

多用用就好了!:)

dym

mongodb已经装好了,能访问了。

[…] Nodejs开发框架Express3.0开发手记–从零开始 […]

jpyee

请教博主,增加bootstrap界面的时候,我的文件夹里面怎么没有bootstrap.min.css、bootstrap-responsive.min.css、bootstrap.min.js和jquery-1.9.1.min.js文件的?

Conan Zhang

这几个文件要自己去下载的。

jpyee

是通过npm install 文件名 这样的方式下载吧?但为什么我下载时会出现以下错误?

Conan Zhang

我的意思是说自己去下载。
http://twitter.github.io/bootstrap/index.html
不是用npm install

jpyee

为什么会出现以下乱码?

Conan Zhang

HTML网页上面是不是没加

jpyee

加了,是如图下面这样子吗

Conan Zhang

1. 你查一下你的页面,是不是统一utf8编码的?
2. 在里加一行中文,看看不是乱码。
3. 这个乱码,是你的传的参数吧?通过console.log在控制台打印一下。

loved_sunshine

res.redirect()为什么要return呢?

Conan Zhang

通过return,告诉程序要转向。如果不加return,这个方法中的程序会继续运行,可能造成多重response。会有错误。

khowarizmi

对于7.session的使用,doLogin确实能够将session的状态传给下一个home,但是我此时返回login时session并没有传递到这个位置。也就是说,想要在登录状态下去往login页面时自动跳转到home应该怎么办?PS:在home页面中,添加如果没有登录,则返回login为佳

Conan Zhang

登陆状态下,不应该访问login。看“9. 页面访问控制”

[…] 在系统中,我们已经安装好了Nodejs和npm。win7安装nodejs请参考文章:Nodejs开发框架Express3.0开发手记–从零开始 […]

[…] 我们直接基于一个Express3的项目进行安装。express的入门,请参考文章:Nodejs开发框架Express3.0开发手记–从零开始 […]

angusw

請問一下 我想要透過 app,use() 去處理所有錯誤 但是我在程式碼中 throw err 整個express 就停止 有什麼地方我沒有設定好嗎 謝謝

Conan Zhang

1. throw err,会抛出异常,程序肯定会就会挂了。
2. 要用try..catch..finally,抓住这个异常。
3. node编程,要避免throw的设计,通过if去处理所有情况。

dagger

在session一节中遇到问题:
TypeError: Cannot read property ‘connect.sid’ of undefined

请教一下。

Conan Zhang

connect.sid依赖于connect的session.
http://blog.fens.me/nodejs-connect/

试试下面的写法
use(connect.cookieParser())
use(connect.session({secret: ‘123’, cookie: { maxAge: 60000 }}))

志强 张

您好丹哥,我很久之前就关注你的网站,第一次是看你的RHadoop系列,在这里学习到了很多很多东西,十分感谢您。《从零开始nodejs》使用了很多方面的技术,我希望您在每次先保证思路清晰的情况下写完一次之后,能够回过头来大致说一下语法,或者给出这些代码的注释,那博文的可读性能提高一些,以适合我这种菜鸟。:-P 谢谢。

Conan Zhang

你好,很高兴文章能帮助你学习。
关于语法的问题,基础学知识是需要自己学习的,而且我是写博客不是写书,所以不可能面面俱到。多花点时间补充自己的基础才是学习之根本!

志强 张

恩恩,我明白了。这篇博文我都实践了一次,我发现最后function notAuthentication(req, res, next)中 若登录了的话就return res.redirect(‘/’);跳转到/下,这样设计的逻辑容易造成疑惑。因为在/下也就index下可以按登录键,可是因为已经登录了所以一直按登录键都没好像没反应一样一直回跳到index也就是本页面。以我愚见还是改成/home比较好一些。不过不改也没关系啦,个人意见而已。

itfan

nodejs 没有MVC中的model?

Conan Zhang

你的问题,有点让人误解? 我试着理解性回答。

1. nodejs一个开发平台
2. express是一个基于nodejs的web开发框架,没有持久层
3. express是一个MVC的框架,数据格式是JSON的,不知道是不是你所有理解的model

itfan

我现在明白nodejs了 谢谢

yunnysunny

node.js是编程语言,类似于java、php

moodpo

晕啊你

itfan

nodejs 是编程语言?搞笑

itfan

看了一段时间 终于明白了 nodejs不是编程语言。。。

多蒙

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

到这里就迷失了。。。咋也调不通

Conan Zhang

显示传值,是指的

exports.home = function(req, res){
var user={
username:’admin’,
password:’admin’
}
res.render(‘home’, { title: ‘Home’,user: user});
};

配置好locals以后,可以简化写法了。

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

ig

博主: “显示”传值 应该是指 “显式”传值吧? 显示会有歧义的

Conan Zhang

谢谢提醒,已改!

denny

看了你的文章,一路顺利通过,学到了很多知识,非常感谢博主的文章。

Conan Zhang

🙂

Leslie

博主,您好! 为什么我在运行到localhost:3000/home的时候,网页显示cannot GET/home呢? 我的代码按照上面一步一步来的..

Leslie

您好。问题已经解决!

Conan Zhang

:)

环

请问你怎么解决的?我也是出现这个问题

lmiky

既然下载了博主代码,那就要留个言,好人一生平安

Conan Zhang

🙂

paul

看了博主的文章, 写的真不错. 受教了, 以后会经常过来学习

Conan Zhang

过奖,:-)

zhyt1985

npm install supervisor 应该为 npm install supervisor -g

Conan Zhang

这到不是什么大问题

zhyt1985

请问我安装了mongodb,也安装了session-mongoose,可是启动nodejs后还是提示“Error: Cannot find module ‘session-mongoose’,这是怎么回事呢?

zhyt1985

解决了,原来是安装session-mongoose时画蛇添足多加了-g

Conan Zhang

🙂

Zhang Danqing

您好:“让ejs模板文件,使用扩展名为html的文件。”这步没有办法进行,已经按照步骤操作后还是只能找到ejs文件,html文件无法运行。。问题就是我在修改app.js和增加ejs这两步的时候都没有报错,但是把index.ejs改成index.html报错了。。现在为止想到的只有自己的express是3.48这个问题,不知道该如何解决,谢谢!!

Zhang Danqing

因为是小白。。。问题好弱,捂脸,还有个问题就是下载了代码但是没有办法运行额额,如图

Conan Zhang

你的mongodb是不是没开?这个是数据库连接的错误。

insCake

怎么开

Conan Zhang

启动mongodb

Zhang Danqing

Hi,我做了些调整,照着你的代码改了一下app.js,可以读取html了。但是好像还是有问题。。只能显示下面的界面,cmd里显示bootstrap已经在读了。。不知道为什么><谢谢了哇XD

Conan Zhang

页面中加载的bootstrap.js

Zhang Danqing

这个调整了下弄好了,刚才copy多了><

Sirus

请问中的footer.html可不可以是动态的?能不能用个变量保存需要include的html地址,然后让include这个变量呢?

zhouyi

志丹哥你好,一开始学习nodejs就参考你的教程,真心不错。我现在遇到一个问题:session在mongodb中没存储成功。能够看到sessions这个集合但是没有数据。后来,我下载了你的源代码来试试,还是没有。

Conan Zhang

找找有没有错误信息

zhouyi

我试过,但是没有。所有的功能正常使用。mongodb客户端是用的mongoHub,运行代码的时候自动生成session和nodejs这两个数据库,可以保存示例的JSON数据到nodejs这个库,但是session这个库下集合(sessions) count的值始终为 0 。

xiaoying

你好,你是怎么把示例成功把保存到nodejs这个库里面的呢?我的问题是一直在mongodb中找不到nodejs这个库,求帮助啊

伟 郑

第四步骤需要反ejs目录改成html,对吧?

Conan Zhang

ejs默认只能识别xxx.ejs的文件,但编辑器打开xxx.ejs没有语法高亮。第四步修改后,可以让ejs支持xxx.html的文件,方便我们编辑。

Peng Jin

您好,我在将显式传值改成session传值的时候出现了问题,

500 TypeError: Cannot set property ‘user’ of undefined,user对象没定义,请问是在哪步出错了?

Conan Zhang

这个错误很普遍,哪都有可能发生。
session.user, req.user, locals.user,这几个变量,跟踪一下吧。

wenhq

我也出现这个问题了。原因是app.js里的顺序。app.js文件有顺序要求,一定要注意!!!

Conan Zhang

似乎都遇到过这个问题。

stepjacky

app.all(‘/login’, notAuthentication);
app.get(‘/login’, routes.login);
app.post(‘/login’, routes.doLogin);
app.get(‘/logout’, authentication);
app.get(‘/logout’, routes.logout);
app.get(‘/home’, authentication);
app.get(‘/home’, routes.home);

node.js
没有像java类似过滤器的功能吗,如果认证需要这么写的话,每个url需要写两次,太弱爆了吧!

Conan Zhang

上面只是一种写法,不懂别乱喷。

类似过滤器实现,如下:
app.get(‘/xxx’, [fun1, fun2,fun3]);

function fun1(a,next){
// code
next();
}

function fun2(a,next){
// code
next();
}

通过next()向后传递。

bigdos

我运行遇到找不到session-mongoose 这个错误,全文如下:
Error: Most middleware (like session) is no longer bundled with Express and must be installed separa
tely. Please see https://github.com/senchalabs/connect#middleware.
at Function.Object.defineProperty.get (G:htdocsmedemonode_modulesexpresslibexpress.js:89:1
3)
at module.exports (G:htdocsmedemonode_modulessession-mongooseindex.js:266:15)
at Object. (G:htdocsmedemoapp.js:10:47)
at Module._compile (module.js:456:26)
at Object.Module._extensions..js (module.js:474:10)
at Module.load (module.js:356:32)
at Function.Module._load (module.js:312:12)
at Module.require (module.js:364:17)
at require (module.js:380:17)
at Object. (G:htdocsmedemobinwww:3:11)
Program node ./bin/www exited with code 8
依赖都安装了,如下:
“dependencies”: {
“express”: “~4.2.0”,
“static-favicon”: “~1.0.0”,
“morgan”: “~1.0.0”,
“cookie-parser”: “~1.0.1”,
“body-parser”: “~1.0.0”,
“debug”: “~0.7.4”,
“ejs”: “~0.8.5”,
“mongodb”: “>=1.3.9”,
“mongoose”: “>=3.8.0”,
“express-partials”: “*”,
“session-mongoose”: “*”
}。不知道什么原因,请帮忙

Mok

我也遇到这样的问题,不知如何处理

Conan Zhang

两种办法,选其一:1. 使用express3.x,按照文章操作。
2. 使用express4.x,用支持的包替换session-mongoose包

haichen

我这里的登录页面的为什么是乱码呢?请指教

Listen

你把所有的js和html文件都用UTF-8编码保存,就可以了,不会有乱码,我也遇到了,我就这样解决了

Sirus

请问中的footer.html可不可以是动态的?能不能用个变量保存需要include的html地址,然后让include这个变量呢?刚才没看清,回复错位置了,不好意思哈。

Conan Zhang

这种写法是ejs的写法,如果不用ejs当然可以做成动态的。从后端传一个变量过来,前端渲染出来。

Sirius

就是说ejs不可以咯?

Conan Zhang

include是EJS语法关键字,不能加载动态的变量。
你可以在footer.html这个文件里,传各种变量,改变内容。

aaa

登陆之后, 重启后端, 登陆还是有效的,登陆信息存在cookie里了, 有没有问题?

Conan Zhang

后端,cookie通过物理介质保存,就是这样的。
如果后端是在内存保存的状态,重启后,用户需要重新登陆。

为了用户体验,都倾向于第一种。

liuwu

你好,实例中用户名和密码都是自定义的。如何将MYSQL数据库查询出来的用户名和密码传过来呢?谢谢

Conan Zhang

你可以参考:

用Nodejs连接MySQL
http://blog.fens.me/nodejs-mysql-intro/

liuwu

你好!页面中为什么要include其它页面,把登录页面写成平时常见html文件时我发现 这个标签无效,访问的登录时候会报错。这有什么办法解决吗?

Conan Zhang

是不是写错了。

liuwu

你没有写错,问题在我。是我用的mysql数据库,mongodb获取SessionStore = require(“session-mongoose”)(express);那么请问mysql数据库怎样获取session!非常感谢你的指导!

Conan Zhang

mysql操作,我没有试过,把存储定位到mysql就行了。

环

博主,安装session-mongoose依赖库,怎样启动它?在那个目录?

环

没有连接上数据库了,不知道怎样启动它

Conan Zhang

mongodb,是一个nosql数据库软件,你需要单独下载安装。

安装和使用,可以参考文章:
http://blog.fens.me/mongodb-master-slave/

MongoDB官方下载
https://www.mongodb.org/downloads

环

mongoose是一个依赖库吗?mongodb和mongoose还有mongodb drive有点搞不清关系

Conan Zhang

mongodb是数据库。
mongoose是nodejs访问mongodb的一种现实,是一个依赖包。

环

不知道为啥出现这个:
TypeError: Cannot read property ‘connect.sess’ of undefined
我直接下载你的源码不会出现这样的问题,我自己添加进去就会遇到这样的问题

Conan Zhang

你最好一行一行地比较一下 app.js 中的代码,找找有哪里写法是不一样的?

栩栩如生

在安装express成功后,却发现express指令用不了,原来最新版本的express命令已经迁移到一个单独的模块express-generetor。。。

Conan Zhang

express 4,我还没有时间看,等过段时间会更新文章的。

栩栩如生

是3.0的,而且官网现在的运行express项目的指令是:$ npm start,不是node app.js,我输入node app.js没有反应。不过看你的文章还真的是获益匪浅,谢谢了~~~~

bin

npm start跟4.0之前的版本node app.js是一样的。你可以看看package.json里面有个scripts参数,其实就是用npm start代替了node app.js。4.0之后的版本把绑定服务器端口的操作移到bin/www下去了。你会发现scripts的参数就是启动这个node ./bin/www。原理就是这份文件作为入口,app.js最后有一句module.exports = app;意思是把app对象作为一个模块,别的文件require这份文件的时候,得到的就是这个app对象。所以www里面有这么一句var app = require(‘../app’);

jalen

真是多谢啊啊。在第一页的时候 我硬是没配出来 ,原来什么都变了…

coder

这个问题是因为最新express4.0版本中将命令工具分家出来了,所以我们还需要安装一个命令工具,命令如下:
npm install -g express-generator

Conan Zhang

这个命令应该是 express 3.6 分出来的。

Servlet

使用cookieSession , 和 session . 我测试了很久,session数据根本就没有持久化到Mongodb数据库里。 全部都是放入到cookie里面了。 这样的话就没有达到数据使用Mongodb的目的

Conan Zhang

session-mongoose

Servlet

我已经测试过了。 如果cookieSession 与 session 同时使用的话,那么程序默认就使用了cookieSession了, 而session是无效的, 也不会持久化到Mongodb里。 只有屏蔽掉cookieSession, 才会持久化到Mongodb里

Conan Zhang

如果你想知道session和cookieSession的区别,看这篇文章:http://blog.fens.me/nodejs-connect/

学超 刘

您好,我是一个刚开始Node.js的新手,请问return res.redirect(‘/login’); 这里的return的作用是什么啊 我试着删除return后程序也可以正常运行。

Conan Zhang

return 表示退出函数,不执行后面的语句了。
如果return res.redirect(‘/home’); 这里不加return,还会执行函数里后面的语句,会出错误的。编程习惯要加return

Dc Zhu

express的session持久化 还是比较方便的,有中间件自动完成,session超时了,找到数据库的data重新恢复session_data,我想问一下,java中tomcat也有关于session store的配置,是如何恢复session_data的呢,有没有相关的中间件什么的去做这样的事?

Conan Zhang

java的session是在内存中的,由容器进行管理,你也可以自己管理sesssion放到redis里。具体的实现要找tomcat的API。

[…] Web开发:express,ejs,hexo, socket.io, restify, cleaver, stylus, browserify,cheerio […]

callmewhy

大哥你咋啥都会!太厉害了。。。

Conan Zhang

多学点,没啥坏处。

callmewhy

你现在在哪里工作,比较好奇你多大了哈哈

Conan Zhang

我在创业中,已经工作很多年了。
看你的博客,你还很年轻,已经做了不少东西了!很好!

callmewhy

很高兴看到你的博客,可以感受的到对编程满满的热爱^_^

Conan Zhang

🙂

Feng Tianba

貌似这使用与express3. express4好像文章中说的很多东西都不行了。。。

Conan Zhang

express3.6 版本以后,做了很多的向前不兼容的升级,文章还没有更新。

Feng Tianba

是的,不过文章还是不错的~能分享很难得~

wise

對新手很有益處,感謝

Conan Zhang

🙂

rong_fan

现在express的版本都是4.x,所以用4.x版本的express完成这个项目真是困难重重,因为3.x版本和4.x版本实在差距很大。于是我还是将版本下调才能顺利完成。。

Conan Zhang

确实,我也没有升级系统呢,从2.x到3就经历了各种折磨。
express4除了替换了connet,没有太多性能或者开发效率上的提升。

再看看,再考虑升级的问题。

Honwhy Wang

希望作者稍作修改,现在安装express不指明版本的话,默认安装的新版4.x。

Conan Zhang

等我有时间,会写一篇介绍express4的文章

萝卜先生

您好,看了您的博客 受益匪浅,但是依然存在一些疑问,目前接触到的项目大部分是MySQL,所以想将您的教程结合MySQL做一下,我也看了您关于MySQL的一些讲解,可是依然对在MySQL下如何使用session有很大的疑问,能否指点一下?

Conan Zhang

MySQL和session没有什么关系,如果用mysql存session就自己写个实现方法,通常情况是没必要这么用的。

202
0
Would love your thoughts, please comment.x
()
x