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);