express应⽤创建及app.js详解
#1 express 应⽤创建
1、安装node.js (⾃⾏百度)
2、npm install express -g
3、全局安装express⽣成器 express-generator
npm install express-generator -g
4、查看 express 版本,可以检查⽣成器 express-generator 是否安装成功
express -v
5、(可选)查看express 所有帮助指令及⽤法
express -h
6、cd 进⼊指定⽬录 workspace(任意命名)--------------这是系统cmd指令,不是node指令
7、在指定⽬录 workspace(任意命名) 创建项⽬ nodejs-demo(任意命名)
express -e nodejs-demo
8、由当前⽬录 workspace(任意命名) 进⼊项⽬⽬录 nodejs-demo(任意命名)--------------这是系统cmd指令,不是node指令
cd workspace
9、安装依赖
npm install
10、启动项⽬
npm start
#2 ⽬录结构# 接下来,我们详细看⼀下Express4项⽬的结构、配置和使⽤。
bin, 存放启动项⽬的脚本⽂件
node_modules, 存放所有的项⽬依赖库。
public,静态⽂件(css,js,img)
routes,路由⽂件(MVC中的C,controller)
views,页⾯⽂件(Ejs模板)
package.json,项⽬依赖配置及开发者信息
app.js,应⽤核⼼配置⽂件
#3 package.json项⽬配置# package.json⽤于项⽬依赖配置及开发者信息,scripts属性是⽤于定义操作命令的,可以⾮常⽅便的增加启动命令,⽐如默认的start,⽤npm start代表执⾏node ./bin/www命令。查看package.json⽂件。
{
"name": "express4-demo",
"version": "0.0.0",
"private": true,
"scripts": {
"start": "node ./bin/www"
},
"dependencies": {
"body-parser": "~1.10.2",
"cookie-parser": "~1.3.3",
"debug": "~2.1.1",
"ejs": "~2.2.3",
"express": "~4.11.1",
"morgan": "~1.5.1",
"serve-favicon": "~2.2.0"
}
}
#4 app.js核⼼⽂件# 从Express3.x升级到Express4.x,主要的变化就在app.js⽂件中。查看app.js⽂件,我已经增加注释说明。
// 加载依赖库,原来这个类库都封装在connect中,现在需地注单独加载
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 routes = require('./routes/index');
//var users = require('./routes/users');
// 创建项⽬实例
var app = express();
// 定义EJS模板引擎和模板⽂件位置,也可以使⽤jade或其他模型引擎
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
// 定义icon图标
app.use(favicon(__dirname + '/public/favicon.ico'));
// 定义⽇志和输出级别
app.use(logger('dev'));
// 定义数据解析器
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
// 定义cookie解析器
app.use(cookieParser());
/
/ 定义静态⽂件⽬录
app.use(express.static(path.join(__dirname, 'public')));
// 匹配路径和路由
app.use('/', routes);
//app.use('/users', users);
// 404错误处理
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
/
/ 开发环境,500错误处理和错误堆栈跟踪
if (('env') === 'development') {
app.use(function(err, req, res, next) {
res.status(err.status || 500);
message: ssage,
error: err
});
});
}
// ⽣产环境,500错误处理
app.use(function(err, req, res, next) {
res.status(err.status || 500);
message: ssage,
error: {}
});
});
// 输出模型app
我们看到在app.js中,原来调⽤connect库的部分都被其他的库所代替,serve-favicon、morgan、cookie-parser、body-parser,默认项⽬中,只⽤到了最基本的⼏个库,还没有其他需要替换的库,在本⽂最后有详细列出。
另外,原来⽤于项⽬启动代码也被移到./bin/www的⽂件,www⽂件也是⼀个node的脚本,⽤于分离配置和启动程序。查看./bin/www⽂件。
#!/usr/bin/env node
/**
* 依赖加载
*/
var app = require('../app');
var debug = require('debug')('nodejs-demo:server');
var http = require('http');
/**
* 定义启动端⼝
*/
var port = v.PORT || '3000');
app.set('port', port);
/**
* 创建HTTP服务器实例
*/
var server = ateServer(app);
/**
* 启动⽹络服务监听端⼝
*/
server.listen(port);
<('error', onError);
<('listening', onListening);
/**
* 端⼝标准化函数
*/
function normalizePort(val) {
var port = parseInt(val, 10);
if (isNaN(port)) {
return val;
}
if (port >= 0) {
return port;
}
return false;
}
/**
* HTTP异常事件处理函数
*/
function onError(error) {
if (error.syscall !== 'listen') {
throw error;
}
var bind = typeof port === 'string'
'Pipe ' + port
: 'Port ' + port
// handle specific listen errors with friendly messages
switch (de) {
case 'EACCES':
<(bind + ' requires elevated privileges');
break;
case 'EADDRINUSE':
<(bind + ' is already in use');
break;
default:
throw error;
}
}
/**
* 事件绑定函数
*/
function onListening() {
var addr = server.address();
var bind = typeof addr === 'string'
'pipe ' + addr
bootstrap项目: 'port ' + addr.port;
debug('Listening on ' + bind);
}
#5 Bootstrap界⾯框架# 创建Bootstrap界⾯框架,直接在index.ejs⽂件上⾯做修改。可以⼿动下载Bootstrap库放到项⽬中对应的位置引⽤,也可以通过bower来管理前端的Javascript库,参考⽂章。另外还可以直接使⽤免费的CDN源加载Bootstrap的css和js⽂件。下⾯我就直接使⽤bower来管理前端的JavaScript库的⽅式。编辑views/index.ejs⽂件:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<title><%= title %></title>
<link rel="stylesheet" href="/bower_components/bootstrap/dist/css/bootstrap.min.css">
<link rel='stylesheet' href='/stylesheets/style.css' />
</head>
<body>
<div class="well jumbotron">
<h1><%= title %></h1>
<p>This is a simple hero unit, a simple jumbotron-style component for calling extra attention to featured content or information.</p>
<p><a class="btn btn-primary btn-lg" href="#" role="button">Learn more</a></p>
</div>
<script src="/bower_components/jquery/dist/jquery.min.js"></script>
<script src="/bower_components/bootstrap/dist/js/bootstrap.min.js"></script>
</body>
</html>
效果如下,已经加⼊了bootstrap的样式了。
接下来,我们把index.ejs页⾯切分成3个部分:header.ejs, index.ejs, footer.ejs,⽤于⽹站页⾯的模块化。
header.ejs, 为页⾯的头部区域
index.ejs, 为内容显⽰区域
footer.ejs, 为页⾯底部区域
编辑header.ejs:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<title><%= title %></title>
<link rel="stylesheet" href="/bower_components/bootstrap/dist/css/bootstrap.min.css">
<link rel='stylesheet' href='/stylesheets/style.css' />
</head>
<body>
编辑footer.ejs:
<script src="/bower_components/jquery/dist/jquery.min.js"></script>
<script src="/bower_components/bootstrap/dist/js/bootstrap.min.js"></script>
</body>
</html>
编辑index.ejs:
<% include header.ejs %>
<div class="well jumbotron">
<h1><%= title %></h1>
<p>This is a simple hero unit, a simple jumbotron-style component for calling extra attention to featured content or information.</p>
<p><a class="btn btn-primary btn-lg" href="#" role="button">Learn more</a></p>
</div>
<% include footer.ejs %>
把页表和页底的代码分离后,让index.ejs页⾯的核⼼代码更少,更容易维护。
#6 路由功能# 路由功能,是Express4以后全⾯改版的功能。在应⽤程序加载隐含路由中间件,不⽤担⼼在中间件被装
载相对于路由器中间件的顺序。定义路由的⽅式是不变的,路由系统中增加2个新的功能。
express.Router类,创建模块化安装路径的处理程序。
head等。
.get(function(req, res, next) {})
.post(function(req, res, next) {})
express.Router类,则可以帮助我们更好的组织代码结构。在app.js⽂件中,定义了app.use(‘/’, routes); routes是指向了routes⽬录下的index.js⽂件,./routes/index.js⽂件
中,express.Router被定义使⽤,路径/*处理都会由routes/index.js⽂件⾥的Router来处理。如果我们要管理不同的路径,那么可以直接配置为多个不同的Router。
app.use('/user', require('./routes/user').user);
app.use('/admin', require('./routes/admin').admin);
app.use('/', require('./routes'));
#7 Ejs模板使⽤# 让ejs模板⽂件,使⽤扩展名为html的⽂件。修改:app.js
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');
#8 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.hodOverride());
app.kieParser());
app.kieSession({secret : ''}));
app.use(express.session({
secret : '',
store: store,
cookie: { maxAge: 900000 }
}));
app.use(function(req, res, next){
res.locals.user = req.session.user;
next();
});
app.uter);
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\
C:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\Microsoft.Cpp.InvalidPlatform.Targets(23,7): erro
r 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)
修改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;
direct('/home');
} else {
direct('/login');
}
};
exports.logout⽅法:
exports.logout = function(req, res){
req.session.user=null;
};
exports.home⽅法:
exports.home = function(req, res){
};
这个时候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是不⼀样的。原理是在框架内每次赋值,把我们刚才⼿动传值的过程,让框架去完成了。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论