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