node.js Web应用框架Express入门指南

一、安装

代码如下:

$ npm install express

或者在任何地方使用可执行的 express(1) 安装:

代码如下:

\# 译注:强烈建议这种方式
$ npm install -g express

二、快速上手

最快上手 express 的方法是利用可执行的 express(1) 来生成一个应用,如下所示:

创建一个 app:


代码如下:

$ npm install -g express
$ express /tmp/foo && cd /tmp/foo

安装依赖包:


代码如下:

$ npm install -d

启动服务器:


代码如下:

$ node app.js

三、创建一个服务器

要创建一个 express.HTTPServer 实例,只需调用 createServer() 方法。 通用这个应用实例,我们可以定义基于 HTTP 动作(HTTP Verbs)的路由,以 app.get() 为例:


代码如下:

var app = require('express').createServer();

app.get('/', function(req, res){
  res.send('hello world');
});

app.listen(3000);

四、创建一个 HTTPS 服务器

如上述初始化一个 express.HTTPSServer 实例。然后我们给它传一个配置对象,接受 key、cert 和其他在 https 文档 所提到的(属性/方法)。


代码如下:

var app = require('express').createServer({ key: ... });

五、配置

Express 支持任意环境,如产品阶段(production)和开发阶段(development)。开发者可以使用 configure() 方法来设置当前所需环境。如果 configure() 的调用不包含任何环境名,它将运行于所有环境中所指定的回调。

译注: 像 production / development / stage 这些别名都是可以自已取的,如 application.js 中的 app.configure 所示。实际用法看下面例子。

下面这个例子仅在开发阶段 dumpExceptions (抛错),并返回堆栈异常。不过在两个环境中我们都使用 methodOverride 和 bodyParser。注意一下 app.router 的使用,它可以(可选)用来加载(mount)程序的路由,另外首次调用 app.get()、app.post() 等也将会加载路由。


代码如下:

app.configure(function(){
    app.use(express.methodOverride());
    app.use(express.bodyParser());
    app.use(app.router);
});

app.configure('development', function(){
    app.use(express.static(__dirname + '/public'));
    app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
});

app.configure('production', function(){
  var oneYear = 31557600000;
  app.use(express.static(__dirname + '/public', { maxAge: oneYear }));
  app.use(express.errorHandler());
});

对于相似的环境你可以传递多个环境字符串:


代码如下:

app.configure('stage', 'prod', function(){
  // config
});

对于任何内部设置(#),Express 提供了 set(key[, val])、 enable(key) 和 disable(key) 方法:

译注:设置详见:application.js 的 app.set。


代码如下:

app.configure(function(){
    app.set('views', __dirname + '/views');
    app.set('views');
    // => "/absolute/path/to/views"

app.enable('some feature');
    // 等价于:app.set('some feature', true);

app.disable('some feature');
    // 等价于:app.set('some feature', false);

app.enabled('some feature')
    // => false
 });

变更环境我们可以设置 NODE_ENV 环境变量,如:


代码如下:

$ NODE_ENV=production node app.js

这非常重要,因为多数缓存机制只在产品阶段是被打开的。

六、设置

Express 支持下列快捷(out of the box)设置:

1.basepath 用于 res.redirect() 的应用程序基本路径(base path),显式地处理绑定的应用程序(transparently handling mounted apps.)
2.view View 默认的根目录为 CWD/views
3.view engine 默认 View 引擎处理(View 文件)并不需要使用后缀
4.view cache 启用 View 缓存 (在产品阶段被启用)
5.charet 改变编码,默认为 utf-8
6.case sensitive routes 路由中区分大小写
7.strit routing 启用后(路由中的)结尾 / 将不会被忽略(译注:即 app.get('/sofish') 和 app.get('/sofish/') 将是不一样的)
8.json callback 启用 res.send() / res.json() 显式的 jsonp 支持(transparent jsonp support)

七、路由

Express 利用 HTTP 动作提供一套提示性强、有表现力的路由 API。打个比方,如果想要处理某个路径为 /user/12 的账号,我们能像下面这样来定义路由。关联到命名占位符(named placeholders)的值可用 req.params 来访问。


代码如下:

app.get('/user/:id', function(req, res){
    res.send('user ' + req.params.id);
});

路由是一个在内部被编译为正则的字符串。譬如,当 /user/:id 被编译,一个简化版本的正则表达弄大概如下:


代码如下:

// 修改一下官方的这个字符串
/\/user\/([^\/]+)\/?/

正则表达式可以传入应用于复杂的场景。由于通过字面量正则表达式捕获的内容组是匿名的,我们可能直接通过 req.params 来访问它们。因此,我们捕获的第一组内容将是 req.params[0],同时第二组是紧接着的 req.params[1]。


代码如下:

app.get(/^\/users?(?:\/(\d+)(?:\.\.(\d+))?)?/, function(req, res){
    res.send(req.params);
});

Curl 针对上述定义路由的请求:


代码如下:

$ curl http://dev:3000/user
[null,null]
$ curl http://dev:3000/users
[null,null]
$ curl http://dev:3000/users/1
["1",null]
$ curl http://dev:3000/users/1..15
["1","15"]

下面是一些路由的实例,关联到他们可能使用到的路径:


代码如下:

"/user/:id"
/user/12

"/users/:id?"
/users/5
/users

"/files/*"
/files/jquery.js
/files/javascripts/jquery.js

"/file/*.*"
/files/jquery.js
/files/javascripts/jquery.js

"/user/:id/:operation?"
/user/1
/user/1/edit

"/products.:format"
/products.json
/products.xml

"/products.:format?"
/products.json
/products.xml
/products

"/user/:id.:format?"
/user/12
/user/12.json

举个例子,我们可以使用 POST 发送 json 数据,通过 bodyParser 这个可以解析 json 请求内容(或者其他内容)的中间件来返回数据,并将返回结果存于 req.body 中:


代码如下:

var express = require('express')
  , app = express.createServer();

app.use(express.bodyParser());

app.post('/', function(req, res){
  res.send(req.body);
});

app.listen(3000);

通常我们可以使用一个像 user/:id 这样,没有(命名)限制的“傻瓜”式的占位符。然而比方说,我们要限制用户 id 只能是数字,那么我们可能使用 /user/:id([0-9]+),这个将仅当占位符是包含至少一位数字时才生效(适配,match)。

八、进路控制(Passing Route Control)

我们可以通过调用第三个参数,next() 函数,来控制下一个适配的路由。如果找不到适配,控制权将会传回给 Connect,同时中间件将会按在 use() 中添加的顺序被依次调用。道理同样适应于多个定义到同一路径的路由,他们将会依次被调用直到其中某个不调用 next() 而决定做出请求响应。


代码如下:

app.get('/users/:id?', function(req, res, next){
    var id = req.params.id;
    if (id) {
        // do something
    } else {
        next();
    }
});

app.get('/users', function(req, res){
    // do something else
});

app.all() 方法只调用一次就可以方便地把同样的逻辑到所有 HTTP 动作。下面我们使用它来从伪数据中提取一个用户,将其赋给 req.user。


代码如下:

var express = require('express')
  , app = express.createServer();

var users = [{ name: 'tj' }];

app.all('/user/:id/:op?', function(req, res, next){
  req.user = users[req.params.id];
  if (req.user) {
    next();
  } else {
    next(new Error('cannot find user ' + req.params.id));
  }
});

app.get('/user/:id', function(req, res){
  res.send('viewing ' + req.user.name);
});

app.get('/user/:id/edit', function(req, res){
  res.send('editing ' + req.user.name);
});

app.put('/user/:id', function(req, res){
  res.send('updating ' + req.user.name);
});

app.get('*', function(req, res){
  res.send(404, 'what???');
});

app.listen(3000);

九、中间件

使用的 Connect 中间件(属性)通常伴随着你的一个常规 Connect 服务器,被传到 express.createServer() 。如:


代码如下:

var express = require('express');

var app = express.createServer(
      express.logger()
    , express.bodyParser()
  );

另外,在 configure() 块内 —— 这个渐进式的宫殿(译注:笑^^,in a progressive manner),我们还可以方便地使用 use() 来添加中间件。


代码如下:

app.use(express.logger({ format: ':method :url' }));

通常,使用 connect 中间件你可能会用到 require('connect'),像这样:


代码如下:

var connect = require('connect');
app.use(connect.logger());
app.use(connect.bodyParser());

这在某种程度上来说有点不爽,所以 express 重导出(re-exports)了这些中间件属性,尽管他们是一样的:


代码如下:

app.use(express.logger());
app.use(express.bodyParser());

中间件的顺序非常重要,当 Connect 收到一个请求,我们传到 createServer() 或者 use() 执行的第一个中间件将附带三个参数,request、response,以及一个回调函数(通常是 next)。当 next() 被调用,将轮到第二个中间件,依此类推。之所以说这是值得注意的,是因为很多中间件彼此依赖,例如 methodOverride() 查询 req.body 方法来检测 HTTP 方法重载,另一方面 bodyParser() 解析请求内容并将其于寄存于 req.body。另一个例子是 cookie 解析和 session 支持,我们必须先 use() cookieParser() 紧接着 session()。

很多 Express 应用都包含这样的一行 app.use(app.router),这看起来可能有点奇怪,其实它仅仅是一个包含所有定义路由规则,并执行基于现有 URL 请求和 HTTP 方法路由查找的一个中间件功能。Express 允许你决定其位置(to position),不过默认情况下它被放置于底部。通过改变路由的位置,我们可以改变中间件的优先级,譬如我们想把错误报告做为最后的中间件,以便任何传给 next() 的异常都可以通过它来处理;又或者我们希望静态文件服务优先级更低,以允许我们的路由可以监听单个静态文件请求的下载次数,等等。这看起来差不多是这样的:


代码如下:

app.use(express.logger(...));
app.use(express.bodyParser(...));
app.use(express.cookieParser(...));
app.use(express.session(...));
app.use(app.router);
app.use(express.static(...));
app.use(express.errorHandler(...));

首先我们添加 logger(),它可能包含 node 的 req.end() 方法,提供我们响应时间的数据。接下来请求的内容将会被解析(如果有数据的话),紧接着的是 cookie 解析和 session 支持,同时 req.session 将会在触发 app.router 中的路由时被定义,这时我们并不调用 next(),因此 static() 中间件将不会知道这个请求,如若已经定义了如下一个路由,我们则可以记录各种状态、拒绝下载和消耗下载点数等。


代码如下:

var downloads = {};

app.use(app.router);
app.use(express.static(__dirname + '/public'));

app.get('/*', function(req, res, next){
  var file = req.params[0];
  downloads[file] = downloads[file] || 0;
  downloads[file]++;
  next();
});

十、路由中间件

路由可以利用路由器中间件,传递一个以上的回调函数(或者数组)到其方法中。这个特性非常有利于限制访问、通过路由下载数据,等等。

通常异步数据检索看起来可能像下例,我们使用 :id 参数,尝试加载一个用户:


代码如下:

app.get('/user/:id', function(req, res, next){
  loadUser(req.params.id, function(err, user){
    if (err) return next(err);
    res.send('Viewing user ' + user.name);
  });
});

为保证 DRY 原则和提升可读,我们可以把这个逻辑应用于一个中间件内。如下所示,抽象这个逻辑到中间件内将允许你重用它,同时保证了我们路由的简洁。


代码如下:

function loadUser(req, res, next) {
  // You would fetch your user from the db
  var user = users[req.params.id];
  if (user) {
    req.user = user;
    next();
  } else {
    next(new Error('Failed to load user ' + req.params.id));
  }
}

app.get('/user/:id', loadUser, function(req, res){
  res.send('Viewing user ' + req.user.name);
});

多重路由可以,并按顺序应用到更深一层的逻辑,如限制一个用户账号的访问。下面的例子只允许通过鉴定的用户才可以编辑他(她)的账号。


代码如下:

function andRestrictToSelf(req, res, next) {
  req.authenticatedUser.id == req.user.id
    ? next()
    : next(new Error('Unauthorized'));
}

app.get('/user/:id/edit', loadUser, andRestrictToSelf, function(req, res){
  res.send('Editing user ' + req.user.name);
});

时刻铭记路由只是简单的函数,如下所示,我们可以定义返回中间件的函数以创建一个更具表现力,更灵活的方案。


代码如下:

function andRestrictTo(role) {
  return function(req, res, next) {
    req.authenticatedUser.role == role
      ? next()
      : next(new Error('Unauthorized'));
  }
}

app.del('/user/:id', loadUser, andRestrictTo('admin'), function(req, res){
  res.send('Deleted user ' + req.user.name);
});

常用的中间件“堆栈”可以通过一个数组来传递(会被递归应用),这些中间件可以混着、匹配到任何层次(which can be mixed and matched to any degree)。


代码如下:

var a = [middleware1, middleware2]
  , b = [middleware3, middleware4]
  , all = [a, b];

app.get('/foo', a, function(){});
app.get('/bar', a, function(){});

app.get('/', a, middleware3, middleware4, function(){});
app.get('/', a, b, function(){});
app.get('/', all, function(){});

对于这个实例的完整代码,请看 route middleware example 这个仓库。

我们可能会有多次想要“跳过”剩余的路由中间件,继续匹配后续的路由。做到这点,我们只需调用 next() 时带上 'route' 字符串 —— next('route')。如果没有余下的路由匹配到请求的 URL,Express 将会返回 404 Not Found。

十一、HTTP 方法

至此已接触了好几次 app.get(),除此这外 Express 还提供了其他常见的 HTTP 动作,如 app.post() 、app.del() 等等。

POST 用法的一个常用例子是提交一个表单。下面我们简单地在 html 中把表单的 method 属性设置为 post,控制权将会指派给它下面所定义的路由。


代码如下:

<form method="post" action="/">
     <input type="text" name="user[name]" />
     <input type="text" name="user[email]" />
     <input type="submit" value="Submit" />
</form>

默认上 Express 并不知道如何处理这个请求的内容,因此我们必须添加 bodyParser 中间件,它将解析 application/x-www-form-urlencoded 和 application/json 请求的内容,并把变量存放于 req.body 中。我们可以像下述示例一样来使用这个中间件:


代码如下:

app.use(express.bodyParser());

如下,我们的路由将有权访问 req.body.user 对象,当有 name 和 email 被定义时它将包含这两个属性(译注:如果表单发送的内容不为空的话)。


代码如下:

app.post('/', function(req, res){
  console.log(req.body.user);
  res.redirect('back');
});

当想在一个表单中使用像 PUT 这样的方法,我们可以使用一个命名为 _method 的 hidden input,它可以用以修改 HTTP 方法。为了做这个,我们首先需要 methodOverride 中间件,它必须出现于 bodyParser 后面,以便使用它的 req.body中所包含的表单值。


代码如下:

app.use(express.bodyParser());
app.use(express.methodOverride());

对于这些方法为何不是默认拥有,简单来说只是因为它并不是 Express 所要求完整功能所必须。方法的使用依赖于你的应用,你可能并不需要它们,客户端依然能使用像 PUT 和 DELETE 这样的方法,你可以直接使用它们,因为 methodOverride 为 form 提供了一个非常不错的解决方案。下面将示范如何使用 PUT 这个方法,看起来可能像:


代码如下:

<form method="post" action="/">
  <input type="hidden" name="_method" value="put" />
  <input type="text" name="user[name]" />
  <input type="text" name="user[email]" />
  <input type="submit" value="Submit" />   
</form>

app.put('/', function(){
    console.log(req.body.user);
    res.redirect('back');
});

十二、错误处理

Express 提供了 app.error() 方法以便接收到的异常在一个路由里抛出,或者传到 next(err) 中。下面这个例子将基于特定的 NotFound 异常处理不同的页面:


代码如下:

function NotFound(msg){
  this.name = 'NotFound';
  Error.call(this, msg);
  Error.captureStackTrace(this, arguments.callee);
}

NotFound.prototype.__proto__ = Error.prototype;

app.get('/404', function(req, res){
  throw new NotFound;
});

app.get('/500', function(req, res){
  throw new Error('keyboard cat!');
});

如下述,我们可以多次调用 app.error()。这里我们检测 NotFound 的实例,并显示 404 页面,或者传到 next 错误处理器。值得注意的是这些处理器可以在任何地方定义,因为他们将会在 listen() 的时候被放置于路由处理器下面。它允许在 configure() 块内有定义,以便我们能基于环境用不同的异常处理方式。


代码如下:

app.error(function(err, req, res, next){
    if (err instanceof NotFound) {
        res.render('404.jade');
    } else {
        next(err);
    }
});

为求简洁(for the simplicity),这里我们假定这个 demo 的所有错误为 500,当然你可以可以选择自己喜欢的。像 node 执行文件系统的系统调用时,你可能会接收到一个带有 ENOENT 的 error.code,意思为 “不存在这样的文件或目录” 的错误,我们可以在错误处理器中使用,或者当有需要时可显示一个指定的页面。


代码如下:

app.error(function(err, req, res){
  res.render('500.jade', {
     error: err
  });
});

我们的 app 同样可以利用 Connect 的 errorHandler 中间件来汇报异常。譬如当我们希望在 “开发” 环境输出 stderr 异常时,我们可以使用:


代码如下:

app.use(express.errorHandler({ dumpExceptions: true }));

同时在开发阶段我们可能需要在花哨的 HTML 页面显示我们传递和抛出的异常,对此我们可以把 showStack 设置为 true。


代码如下:

app.use(express.errorHandler({ showStack: true, dumpExceptions: true }));

errorHandler 中间件还可以在 Accept: application/json 存在的时候返回 json,这对于开发重度依赖客户端 Javascript 的应用非常有用。

十三、Route 参数预处理

路由参数预处理,通过隐式数据加载和请求验证,可以大大提升你程序的可读性。打个比方,你通常需要持续地从多个路由获取基本数据。像用 /user/:id 加载一个用户,通常来说我们可能会这样干:


代码如下:

app.get('/user/:userId', function(req, res, next){
  User.get(req.params.userId, function(err, user){
    if (err) return next(err);
    res.send('user ' + user.name);
  });
});

通过预处理,我们的参数可以映射到执行验证、控制(coercion),甚至从数据库加载数据的回调。如下我们带着参数名调用 app.param() 希望将其映射于某些中间件。如你所见,我们接受代表占位符值的 id 参数。使用这个,我们如常加载用户并处理错误,以及简单地调用 next() 来把控制权交由下一个预处理或者路由处理器。


代码如下:

app.param('userId', function(req, res, next, id){
  User.get(id, function(err, user){
    if (err) return next(err);
    if (!user) return next(new Error('failed to find user'));
    req.user = user;
    next();
  });
});

一旦这样做,上所述将会大大地提升路由的可读性,并且允许我们轻松地在整个程序中共享逻辑:


代码如下:

app.get('/user/:userId', function(req, res){
  res.send('user ' + req.user.name);
});

十四、View 处理

View 文件件使用 <name>.<engine> 这样的格式,其中 <engine> 是被 require 进来模块的名。例如 layout.ejs 将告诉 view 系统去 require('ejs'),被加载的模块必须(导出) exports.compile(str, options) 方法,并返回一个 Function 来适应 Express。app.register() 可用以改变这种默认行为,将文件扩展名映射到特定的引擎。譬如 “foo.html” 可以由 ejs 来处理。

下面这个例子使用 Jade 来处理 index.html。因为我们并未使用 layout: false,index.jade 处理后的内容将会被传入到 layout.jade 中一个名为 body 的本地变量。


代码如下:

app.get('/', function(req, res){
    res.render('index.jade', { title: 'My Site' });
});

新的 view engine 设置允许我们指定默认的模板引擎,例如当我们使用 jade 时可以这样设置:


代码如下:

app.set('view engine', 'jade');

允许我们这样处理:


代码如下:

res.render('index');

对应于:


代码如下:

res.render('index.jade');

当 view engine 被设定,扩展名实属可选,但我们依然可以混着匹配模板引擎:


代码如下:

res.render('another-page.ejs');

Express 同时还提供了 view options 设置,这将应用于一个 view 每次被渲染的时候,譬如你不希望使用 layouts 的时候可能会这样做:


代码如下:

app.set('view options', {
    layout: false
});

在需要的时候,这可以在 res.render() 调用的内部进行重载:


代码如下:

res.render('myview.ejs', { layout: true });

当有需要变更一个 layout,我们通常需要再指定一个路径。譬如当我们已经把 view engine 设置为 jade,并且这个文件命名为 ./views/mylayout.jade,我们可以这样简单地进行传参:


代码如下:

res.render('page', { layout: 'mylayout' });

否则(译注:没有把 view engine 设置为 jade 或者其他的引擎时),我们必须指定一个扩展名:


代码如下:

res.render('page', { layout: 'mylayout.jade' });

它们同样可以是绝对路径:


代码如下:

res.render('page', { layout: __dirname + '/../../mylayout.jade' });

对于这点有一个不错的例子 —— 自定义 ejs 的起始和闭合标签:


代码如下:

app.set('view options', {
    open: '{{',
    close: '}}'
})

十五、View 部件

Express 的 view 系统内置了部件(partials) 和集合器(collections)的支持,相当于用一个 “迷你” 的 view 替换一个文档碎片(document fragment)。示例,在一个 view 中重复渲染来显示评论,我们可以使用部件集:


代码如下:

partial('comment', { collection: comments });

如果并不需要其他选项或者本地变量,我们可以省略整个对象,简单地传进一个数组,这与上述是等价的:


代码如下:

partial('comment', comments);

在使用中,部件集无偿地提供了一些 “神奇” 本地变量的支持:

1.firstInCollection true,当它是第一个对象的时候
2.indexInCollection 在集合器对象中的索引
3.lastInCollection true,当它是最后一个对象的时候
4.collectionLength 集合器对象的长度

本地变量的传递(生成)具备更高的优先级,同时,传到父级 view 的本地变量对于子级 view 同样适应。例如当我们用 partial('blog/post', post) 来渲染一个博客文章,它将会生成一个 post 本地变量,在调用这个函数的 view 中存在本地变量 user,它将同样对 blog/post 有效。(译注:这里 partial 比较像 php 中的 include 方法)。

注意: 请谨慎使用部件集合器,渲染一个长度为 100 的部件集合数组相当于我们需要处理 100 个 view。对于简单的集合,最好重复内置,而非使用部件集合器以避免开销过大。

十六、View 查找

View 查找相对于父级 view (路径)执行,如我们有一个 view 页面叫作 views/user/list.jade,并且在其内部写有 partial('edit') 则它会尝试加载 views/user/edit.jade,同理 partial('../messages') 将会加载 views/messages.jade。

View 系统还支持模板索引,允许你使用一个与 view 同名的目录。例如在一个路由中,res.render('users') 得到的非 views/users.jade 即 views/users/index.jade。(译注:先处理 <path>.<engine> 的情况,再处理 <path>/<index.<engine> 的情况,详情可见 view.js。)

当使用上述 view 索引,我们在与 view 同一个目录下,使用 partial('users') 中引用 views/users/index.jade,与此同时 view 系统会尝试索引 ../users/index,而无须我们调用 partial('users')。

十七、Template Engines

下列为 Express 最常用的模板引擎:

1.Haml:haml 实现
2.Jade:haml.js 继位者
3.EJS:嵌入式 JavaScript
4.CoffeeKup:基于 CoffeeScript 的模板
5.jQuery Templates

十八、Session 支持

Session 支持可以通过使用 Connect 的 session 中间件来获得,为此通常我们同时需要在其前加上 cookieParser 中间件,它将解析和存储 cookie 数据于 req.cookies 中。


代码如下:

app.use(express.cookieParser());
app.use(express.session({ secret: "keyboard cat" }));

默认情况下 session 中间件使用 Connect 内置的内存存储,然而还有其他多种实现方式。如 connect-redis 提供了一种 Redis 的 session 存储,它这可像下面这样被使用:


代码如下:

var RedisStore = require('connect-redis')(express);
app.use(express.cookieParser());
app.use(express.session({ secret: "keyboard cat", store: new RedisStore }));

至此,req.session 和 req.sessionStore 属性将可以被所有路由和后继的中间件使用。在 req.session 上的所有属性都会在一个响应中被自动保存下来,譬如当我们想要添加数据到购物车:


代码如下:

var RedisStore = require('connect-redis')(express);
app.use(express.bodyParser());
app.use(express.cookieParser());
app.use(express.session({ secret: "keyboard cat", store: new RedisStore }));

app.post('/add-to-cart', function(req, res){
  // 我们可能通过一个表单 POST 出多个 item
  // (在些使用 bodyParser() 中间件)
  var items = req.body.items;
  req.session.items = items;
  res.redirect('back');
});

app.get('/add-to-cart', function(req, res){
  // 当返回时,页面 GET /add-to-cart
  // 我们可以检查 req.session.items && req.session.items.length
  // 来打印出提示
  if (req.session.items && req.session.items.length) {
    req.notify('info', 'You have %s items in your cart', req.session.items.length);
  }
  res.render('shopping-cart');
});

对于 req.session 对旬,它还有像 Session#touch()、Session#destroy()、 Session#regenerate() 等用以维护和操作 session 的方法。更多的详情请看 Connect Session 的文档。

十九、升级指南

对于使用 Express 1.x 的同学,如果你有很重要的程序需要升级到 2.x 以获得更好的支持,请看官方非常详细的迁移指南:http://expressjs.com/guide.html#migration-guide

(0)

相关推荐

  • Node.js和Express简单入门介绍

    仅仅入门如何用Node.js和Express搭建一个web服务器,没有说明太多概念性的东西. 一. Nodejs简介 ​ ==Node是JavaScript语言的服务器运行环境.== ​ 所谓"运行环境"有两层意思:首先,JavaScript语言通过Node在服务器运行,在这个意义上,Node有点像JavaScript虚拟机:其次,Node提供大量工具库,使得JavaScript语言与操作系统互动(比如读写文件.新建子进程),在这个意义上,Node又是JavaScript的工具库. ​

  • Node.js+Express配置入门教程详解

    Node.js是一个Javascript运行环境(runtime).实际上它是对Google V8引擎进行了封装.V8引 擎执行Javascript的速度非常快,性能非常好.Node.js对一些特殊用例进行了优化,提供了替代的API,使得V8在非浏览器环境下运行得更好.Node.js是一个基于Chrome JavaScript运行时建立的平台, 用于方便地搭建响应速度快.易于扩展的网络应用.Node.js 使用事件驱动, 非阻塞I/O 模型而得以轻量和高效,非常适合在分布式设备上运行的数据密集型

  • Node.js的Express框架使用上手指南

    Express介绍 npm提供了大量的第三方模块,其中不乏许多Web框架,比如我们本章节要讲述的一个轻量级的Web框架 --- Express. Express是一个简洁.灵活的node.js Web应用开发框架, 它提供一系列强大的功能,比如:模板解析.静态文件服务.中间件.路由控制等等,并且还可以使用插件或整合其他模块来帮助你创建各种 Web和移动设备应用,是目前最流行的基于Node.js的Web开发框架,并且支持Ejs.jade等多种模板,可以快速地搭建一个具有完整功能的网站. 好,下面我

  • 从零学习node.js之express入门(六)

    一. 介绍 什么是express,为什么要使用express?根据官方网站的说法,express是一个基于 Node.js 平台的极简.灵活的web应用开发框架,它提供一系列强大的特性.丰富的API接口,对web应用的接口进行了二次的封装,提供了MVC模式,方便我们可以快速地创建各种web和移动应用. Express 框架核心特性: 可以设置中间件来响应 HTTP 请求. 定义了路由表用于执行不同的 HTTP 请求动作. 可以通过向模板传递参数来动态渲染 HTML 页面. 本文也只是简单的了解下

  • node.js express中app.param的用法详解

    前言 大家应该都知道,express中app.param方法用于验证参数,我个人把它理解成类似对参数过滤的一个中间件.在这里我来结合几个demo,加深大家对app.param方法的理解.下面话不多说,来一起通过示例代码看看详细的介绍吧. demo1: var express = require('express'); var app = express(); app.param(function(param, option) { return function (req, res, next,

  • node.js Web应用框架Express入门指南

    一.安装 复制代码 代码如下: $ npm install express 或者在任何地方使用可执行的 express(1) 安装: 复制代码 代码如下: \# 译注:强烈建议这种方式$ npm install -g express 二.快速上手 最快上手 express 的方法是利用可执行的 express(1) 来生成一个应用,如下所示: 创建一个 app: 复制代码 代码如下: $ npm install -g express$ express /tmp/foo && cd /tmp

  • Node.js开源应用框架HapiJS介绍

    一.HapiJS介绍 HapiJS是一个开源的.基于Node.js的应用框架,它适用于构建应用程序和服务,其设计目标是让开发者把精力集中于开发可重用的应用程序的业务逻辑,向开发者提供构建应用程序业务逻辑所需的基础设施.HapiJS目前的最新版本为7.2.0版. 二.HapiJS安装和项目配置 1.安装Hapi库 HapiJS的安装很简单,执行如下命令: 复制代码 代码如下: $ sudo npm install hapi -g hapi@7.2.0 /usr/local/lib/node_mod

  • Node.js web 应用如何封装到Docker容器中

    小小又开始学习新的内容了.这次学习的是,把一个Node.js 应用封装到Docker容器,完成本教程的前提是拥有一个可以安装的,已经正常可以工作的Docker.以及对Node.js应用如何工作,有一个大致的了解. 本教程的第一部分,需要创建一个Web应用程序,然后为这个应用程序构建一个Docker镜像,最后把这个镜像作为容器进行运行. Docker允许应用对依赖进行打包完成一个标准化的单元,这是一个容器,对于应用而言,Docker被称为一个标准的Linux操作系统,一个镜像是进行加载到容器的软件

  • 优化Node.js Web应用运行速度的10个技巧

    Node.js 受益于它的事件驱动和异步的特征,已经很快了.但是,在现代网络中只是快是不行的.如果你打算用 Node.js 开发你的下一个Web 应用的话,那么你就应该无所不用其极,让你的应用更快,异常的快.本文将介绍 10 条,经过检验得知可大大提高 Node 应用的技巧.废话不多说,让我们逐条来看看. 1. 并行 创建 Web 应用的时候,你可能要多次调用内部 API 来获取各种数据.比如说,假设在 Dashboard 页面上,你要执行下面这几个调用: 用户信息 -getUserProfil

  • node.js中的socket.io入门实例

    关于websocket等反向ajax技术介绍 在实时web应用中,常见的方法是反向Ajax.反向Ajax的定义: 反向Ajax(Reverse Ajax)本质上则是这样的一种概念:能够从服务器端向客户端发送数据.在一个标准的HTTP Ajax请求中,数据是发送给服务器端的,反向Ajax可以某些特定的方式来模拟发出一个Ajax请求,这些方式本文都会论及,这样的话,服务器就可以尽可能快地向客户端发送事件(低延迟通信). 反向Ajax技术主要有两点内容:一是服务器端保持住TCP连接直到其有数据发送给客

  • 如何从头实现一个node.js的koa框架

    前言 koa.js是最流行的node.js后端框架之一,有很多网站都使用koa进行开发,同时社区也涌现出了一大批基于koa封装的企业级框架.然而,在这些亮眼的成绩背后,作为核心引擎的koa代码库本身,却非常的精简,不得不让人惊叹于其巧妙的设计. 在平时的工作开发中,笔者是koa的重度用户,因此对其背后的原理自然也是非常感兴趣,因此在闲暇之余进行了研究.不过本篇文章,并不是源码分析,而是从相反的角度,向大家展示如何从头开发实现一个koa框架,在这个过程中,koa中最重要的几个概念和原理都会得到展现

  • node.js WEB开发中图片验证码的实现方法

    用node做web开发很多都可能碰到需要验证码的地方,之前在github上搜索,有一些比如node-captcha等的类库,都需要依赖第三方的图形处理库或者软件,像我之前安装cario这个图形库时,真是费了好大一番劲,但是其实我们只用到了这些图形库的一点点小功能,比如图片的尺寸修改裁剪,或者生产验证码. 先介绍一下CImg这个c++的图形库吧,CImg是一个跨平台的C++的图像处理库,提供了加载.处理.显示.保存等一系列功能,最吸引人的地方是整个图形库就一个CImg.h这个文件,所以非常的便携绿

  • Node.js的Koa框架上手及MySQL操作指南

    由 Express 原班人马打造的 koa,致力于成为一个更小.更健壮.更富有表现力的 Web 框架.使用 koa 编写 web 应用,通过组合不同的 generator,可以免除重复繁琐的回调函数嵌套,并极大地提升常用错误处理效率.Koa 不在内核方法中绑定任何中间件,它仅仅提供了一个轻量优雅的函数库,使得编写 Web 应用变得得心应手. 安装koa koa 依赖支持 generator 的 Node 环境,也就是说,node的版本要在 0.11.9 或者更高,否则将无法执行. 用npm: $

  • node.js中EJS 模板快速入门教程

    Node 开源模板的选择很多,但推荐像我这样的老人去用 EJS,有 Classic ASP/PHP/JSP 的经验用起 EJS 来的确可以很自然,也就是说,你能够在 <%...%> 块中安排 JavaScript 代码,利用最传统的方式 <%=输出变量%>(另外 <%-输出变量是不会对 & 等符号进行转义的).安装 EJS 命令如下: npm install ejs JS 调用 JS 调用的方法主要有两个: ejs.compile(str, options); //

  • Node.js使用Express.Router的方法

    在实际开发中通常有几十甚至上百的路由,都写在 index.js 既臃肿又不好维护,这时可以使用 express.Router 实现更优雅的路由解决方案. 目录结构如下: routes的index.js代码如下: const express = require('express') const router = express.Router() router.get('/', function (req, res) { res.send('hello, express') }) module.ex

随机推荐