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

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 的本地变量。

复制代码 代码如下:

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wgpfww.html