Express blog从零开始搭建(2)

package.json


{
    ...
    "scripts": {
        "start": "node ./bin/www   // 指定执行脚本
    },
    "dependencies": {
        "body-parser": ...,     
        "cookie-parser": ...,   
        "debug": ...,           
        "ejs": ...,             
        "express": ...,         
        "morgan": ...,          
        "serve-favicon": ...    
    }
}

body-parser: express中间件,作用是对post请求的请求体进行解析。
cookie-parser: express中间件,解析cookies
debug: 仿照nodejs核心调试技术的一个小型JavaScript调试工具。
ejs: 视图模板渲染引擎
express: nodejs web应用程序框架
morgan: nodejs http请求日志中间件
serve-favicon: nodejs 提供favicon的中间件

app.js


  • 设置视图模板渲染引擎
// 指定渲染引擎目录
app.set('views', path.join(__dirname, 'views');
// 指定渲染引擎
app.set('view engine', 'ejs');

回溯: Express blog从零开始搭建(1)中使用express -v -e .命令时,app.js中指定渲染引擎的代码为app.set('view engine', '-e'),并不是我们期望的ejs视图模板引擎,因为当使用-v参数时不能使用ejs的简写指令-e

  • 使用morgan打印日志
app.use(logger('dev'));

实现终端打印日志, dev参数,可以看morgan的源码:

/**
 * dev (colored)
 */

morgan.format('dev', function developmentFormatLine (tokens, req, res) {
  // get the status code if response written
  var status = headersSent(res)
    ? res.statusCode
    : undefined

  // get status color
  var color = status >= 500 ? 31 // red
    : status >= 400 ? 33 // yellow
    : status >= 300 ? 36 // cyan
    : status >= 200 ? 32 // green
    : 0 // no color

  // get colored function
  var fn = developmentFormatLine[color]

  if (!fn) {
    // compile
    fn = developmentFormatLine[color] = compile('\x1b[0m:method :url \x1b[' +
      color + 'm:status \x1b[0m:response-time ms - :res[content-length]\x1b[0m')
  }

  return fn(tokens, req, res)
})

这里注释说明是以高亮的形式在终端输出日志。这里如果不确定dev参数的用处,可以去掉,即直接使用app.use(logger()),然后就会在控制台获得如下报错信息:

morgan deprecated undefined format: specify a format app.js:19:9
morgan deprecated default format: use combined format app.js:19:9

使用express-generate生成的express项目中使用到的中间件或依赖包,还是需要做了解的。在不关心细节的情况下,可以根据上面抛出的异常去查看源码支持的几种format。

function morgan(format, options) {
    ...
    return function logger(req, res, next) {
        ....
    }
}

morgan最后返回的是一个命名为logger的中间件。

  • 使用body-parser解析post请求的请求体
app.use(bodyParser.json());     // 加载解析json的中间件
app.use(bodyParser.urlencoded({ extended: false })); // 加载解析urlencoded的中间件

bodyParser.json()解析json格式的数据
bodyParser.urlencoded()解析form表单提交的数据,也就是请求头中包含: Content-Type: application/x-www-form-urlencoded

回顾一下Content-Type的四种类型:
1. application/x-www-form-urlencoded 常见的表单提交
2. multipart/form-data 文件提交
3. application/json json格式数据
4. text/xml xml格式数据

  • 加载解析cookie的中间件
app.use(cookieParser());
  • 设置public为静态资源存放的目录
app.use(express.static(path.join(__dirname, 'public')));
  • 路由
app.use('/', index);
app.use('/users', users);
  • 捕获404并转发到错误处理程序
app.use(function(req, res, next)) {
    var err = new Error('Not Found');
    error.status = 404;
    // 转发到错误处理程序
    next(err);
}

因为没有做特殊的处理,JavaScript的Error对象的所有公共属性都会暴露。

  • 错误处理程序
app.use(function(err, req, res, next) {
    // 设置locals,只在开发环境中呈现错误信息
    res.locals.message = err.message;    // 设置locals错误信息
    res.locals.error = req.app.get('env') === 'development' ? err : {};     // 设置locals的error对象为error
    // 渲染错误页面
    res.status(err.status || 500);    // 填充res的状态码,程序未处理的返回500
    res.render('error');      // express/lib/response.js [res.render = function render(view, options, callback)]
});

与error页面呈现的信息对应一下:

<h1><%= message %></h1>         // 错误信息
<h2><%= error.status %></h2>    // 错误状态码
<pre><%= error.stack %></pre>   // 错误堆栈信息,这里是具体的错误信息

res.render('error');点明将会渲染的视图,如果即将渲染的视图路由不存在时,则会调用内置的错误处理程序。
如果访问一个不存在的路由,内置的错误处理程序不会将路由重定向到某个路由,而是直接将错误信息打印在当前并不存在的路由页面中,使得看上去是当前访问的路由呈现的错误信息。
访问不存在的路由

module.exports = app; // 将app.js作为模块导出
  • 内置错误处理程序

Express内置的错误处理程序,负责处理应用程序中可能遇到的任何错误,这个内置的错误处理中间件函数添加在中间件函数集的末尾。

原因:
如果将错误传递给next()且未在自定义的错误处理程序中处理,则将由内置的错误处理程序处理;错误将写入客户端的堆栈跟踪内。堆栈跟踪并不存在于生产环境。
在生产环境中,如果在响应之后调用next()时出错,express的内置错误处理程序会关闭连接并使请求失败。因此在自定义错误处理程序时,如果响应头已经发送到客户端,要考虑委托给内置错误处理程序处理。

bin/www


  • 文件声明
#!/usr/bin/env node

声明是node可执行文件

  • 设置端口
var port = normalizePort(process.env.PORT || 3000);
app.set('port', port);

如果设置了process.env.PORT,对其序列化并使用;否则使用默认端口3000。

  • 创建HTTP服务器
var server = http.createServer(app);
  • 监听端口
server.listen(port);
  • HTTP server的error和listening事件监听
server.on('error', onError);
server.on('listening', onListening);
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章