脚手架
大多数项目都需要一定数量的“套路化”代码,所有可以创建一个通用的项目骨架,每次开始新项目时,只需复制这个骨架,或者说是模板。
RoR把这个概念向前推进了一步,它提供了一个可以自动生成脚手架的程序。相对于从一堆模板中作出选择,这种方式的优点是可以生成更复杂的框架;Express借鉴了RoR的这一做法,提供了一个生成脚手架的工具,从而可以让你开始一个新的Express项目。
开始创建一个项目
初步配置
- 先给你的项目创建一个新目录,这将作为项目的根目录。
- npm在package.json文件中管理项目的依赖项以及项目的元数据。要创建这个文件,最简单的办法是运行
npm init
。
注意:如果你的package.json文件中没有指定一个存储库的URL,以及一个非空的README.md文件,那么你每次运行npm时都会看到警告信息。
- 安装Express:
npm install --save express
; 运行npm install会把指定名称的包安装到node_modules目录下。如果你用了--save选项,它还会更新package.json文件。 - 因为node_modules随时都可以用npm重新生成,所以我们不会把这个目录保存在我们的代码库中。为了确保不把它添加到代码库中, 我们可以创建一个.gitignore文件:
node_modules
- 接下来创建meadowlark.js文件,这是我们项目的入口。
大多数人会把主文件命名为app.js/index.js/server.js;不过考虑到可能的冲突,除非你用的托管服务或部署系统对程序主文件的名称有特定的要求,更倾向于按照项目命名主文件。npm init默认是用index.js,如果要使用其他的主文件名,要记得修改package.json文件中的main属性。
var express = require('express');
var app = express();
//这样设置可以在启动服务器前通过设置环境变量覆盖端口
app.set('port', process.env.PORT || 3000);
app.get('/', function(req, res) {
res.type('text/plain');
res.send('Medaowlark Travel');
});
app.get('/about', function(req, res) {
res.type('text/plain');
res.send('About Medaowlark Travel');
});
//定制404页面
app.use(function(req, res) {
res.type('text/plain');
res.status(404);
res.end('404-Not Found');
});
//定制500页面
app.use(function(err, req, res, next) {
console.error(err.stack);
res.type('text/plain');
res.status(500);
res.send('500 - Server Error');
});
app.listen(app.get('port'), function() {
console.log('Express started on http://localhost:' +
app.get('port') + '; press Ctrl-C to terminate.');
});
- 在Express文档中的
app.VERB
,VERB用来指代HTTP动词的(最常见的是“get” 和“post”)。这个方法有两个参数:一个路径和一个函数。
路由就是由这个路径定义的。app.VERB帮我们做了很多工作:它默认忽略了大小写或反斜杠,并且在进行匹配时也不考虑查询字符串。所以针对关于页面的路由对于/about、/About、/about/、/about?foo=bar、/about/?foo=bar等路径都适用。(就不需要之前那样处理路径了)** - 这次使用的不是Node的
res.end
,而是换成了Express的扩展res.send
。 - 用
res.status
和res.type
替换了Node的res.writeHead。 - 注意,我们对定制的404和500页面的处理与对普通页面的处理应有所区别:用的不是
app.get
,而是app.use
。app.use
是Express添加中间件的一种方法,现在你可以把它看作处理所有没有路由匹配路径的处理器。
注意,在Express中,路由和中间件的添加顺序至关重要。如果我们把404处理器放在所有路由上面,那首页和关于页面就不能用了,访问这些URL得到的都是404;下面的例子,第一个路径会覆盖其他路径
app.get('/about*',function(req,res){
// 发送内容....
})
app.get('/about/contact',function(req,res){
// 发送内容....
})
app.get('/about/directions',function(req,res){
// 发送内容....
})
视图和布局
视图本质上是要发送给用户的东西。对网站而言,视图通常就是HTML;视图与静态资源(比如图片或CSS文件)的区别是它不一定是静态的:HTML可以动态构建,为每个请求提供定制的页面。
Express支持多种不同的视图引擎,如jade,ejs等,这里使用Handlebars
- 安装
npm install --save express3-handlebars
- 添加代码
var hanlebars = require('express3-handlebars').create({defaultLayout: 'main'});
app.engine('hanlebars', hanlebars.engine);
app.set('view engine', 'hanlebars');
这段代码创建了一个视图引擎,并对Express进行了配置,将其作为默认的视图引擎。接下来创建views目录,在其中创建一个子目录layouts。布局概念(有时也被称为“母版页”),在开发网站时,每个页面上肯定有一定数量的HTML是相同的,或者非常相近。在每个页面上重复写这些代码不仅非常繁琐,还会导致潜在的维护困境:如果你想在每个页面上做一些修改,那就要修改所有文件。布局可以解决这个问题,它为网站上的所有页面提供了一个通用的框架。
- 创建一个views/layouts/main.handlebars文件
<!doctype html>
<html>
<head>
<title>Meadowlark Travel</title>
</head>
<body>
{{{body}}}
</body>
</html>
{{{body}}},这个表达式会被每个视图自己的HTML取代。在创建Handlebars实例时,我们指明了默认布局(defaultLayout:'main')。这就意味着除非你特别指明,否则所有视图用的都是这个布局。
- 创建 views/home.handlebars:
<h1>Welcome to Meadowlark Travel</h1>
- 创建 views/about.handlebars:
<h1>About Meadowlark Travel</h1>
- 创建 views/404.handlebars:
<h1>404 - Not Found</h1>
- 服务器错误页面,views/500.handlebars:
<h1>500 - Server Error</h1>
*接下来必须将使用这些视图的新路由替换旧路由:
app.get('/', function(req, res) {
res.render('home');
});
app.get('/about', function(req, res) {
res.render('about');
});
// 404 catch-all处理器(中间件)
app.use(function(req, res, next) {
res.status(404);
res.render('404');
});
// 500错误处理器(中间件)
app.use(function(err, req, res, next) {
console.error(err.stack);
res.status(500);
res.render('500');
});
视图引擎默认会返回text/html的内容类型和200的状态码。在catch-all处理器(提供定制的404页面)以及500处理器中,我们必须明确设定状态码。
视图和静态文件
Express靠中间件处理静态文件和视图;现在只需了解中间件是一种模块化手段,它使得请求的处理更加容易。
*static
中间件可以将一个或多个目录指派为包含静态资源的目录,其中的资源不经过任何特殊处理直接发送到客户端。
在项目目录下创建名为public的子目录 (因为这个目录中的所有文件都会直接对外开放,所以我们称这个目录为public)。接下来,你应该把static
中间件加在所有路由之前:
app.use(express.static(__dirname + '/public'));
static
中间件相当于给你想要发送的所有静态文件创建了一个路由,渲染文件并发送给客户端。
视图中的动态内容
视图真正的强大之处在于它可以包含动态信息。我们在meadowlark.js中定义一个幸运饼干数组:
var fortunes = [
"Conquer your fears or they will conquer you.",
"Rivers need springs.",
"Do not fear what you don't know.",
"You will have a pleasant surprise.", "Whenever possible, keep it simple.",
];
修改视图(/views/about.handlebars)以显示幸运饼干:
<p>Your fortune for the day:</p>
<blockquote>{{fortune}}</blockquote>
修改路由/about,随机发送幸运饼干:
app.get('/about', function(req, res) {
var randomFortune = fortunes[Math.floor(Math.random() * fortunes.length)];
res.render('about', { fortune: randomFortune });
});