express的新開發人員每每對路由處理程序和中間件之間的區別感到困惑。所以他們也對app.use()
,app.all()
,app.get()
,app.post()
,app.delete()
和app.put()
方法的區別感到困惑。express
在本文中,我將解釋中間件和路由處理程序之間的區別。以及如何正確使用app.use()
,app.all()
,app.get()
,app.post()
,app.delete()
和app.put()
方法。app
app.use()
,app.all()
,app.get()
,app.post()
,app.delete()
和app.put()
所有是用來定義路由的。這些方法都用於定義路由。路由用於處理HTTP請求。路由是路徑和回調的組合,在請求的路徑匹配時執行。回調被稱爲路由處理程序。函數
它們之間的區別是處理不一樣類型的HTTP請求。例如: app.get()
方法僅僅處理get請求,而app.all()
處理GET、POST等請求。post
下面是一個例子,如何定義一個路由:
var app = require("express")(); app.get("/", function(req, res, next){ res.send("Hello World!!!!"); }); app.listen(8080);
每一個路由處理程序都得到對當前正在提供的HTTP請求的請求和響應對象的引用。ui
能夠爲單個HTTP請求執行多個路由處理程序。這是一個例子:
var app = require("express")(); app.get("/", function(req, res, next){ res.write("Hello"); next(); }); app.get("/", function(req, res, next){ res.write(" World !!!"); res.end(); }); app.listen(8080);
這裏第一個句柄寫入一些響應,而後調用next()
。 next()
方法用於調用與路徑路徑匹配的下一個路由處理程序。this
路由處理程序必須結束請求或調用下一個路由處理程序。url
咱們還能夠將多個路由處理程序傳遞給app.all()
,app.get()
,app.post()
,app.delete()
和app.put()
方法。code
這是一個證實這一點的例子:
var app = require("express")(); app.get("/", function(req, res, next){ res.write("Hello"); next(); }, function(req, res, next){ res.write(" World !!!"); res.end(); }); app.listen(8080);
中間件是一個位於實際請求處理程序之上的回調。它採用與路由處理程序相同的參數。中間件
要了解中間件,咱們來看一個帶有dashboard
和profile
頁面的示例站點。要訪問這些頁面,用戶必須登陸。還會記錄對這些頁面的請求。對象
如下是這些頁面的路由處理程序的代碼:
var app = require("express")(); function checkLogin(){ return false; } function logRequest(){ console.log("New request"); } app.get("/dashboard", function(req, res, next){ logRequest(); if(checkLogin()){ res.send("This is the dashboard page"); } else{ res.send("You are not logged in!!!"); } }); app.get("/profile", function(req, res, next){ logRequest(); if(checkLogin()){ res.send("This is the dashboard page"); } else{ res.send("You are not logged in!!!"); } }); app.listen(8080);
這裏的問題是有不少重複的代碼,即咱們不得很少次使用logRequest()
和checkLogin()
函數。這也使得更新代碼變得困難。所以,爲了解決這個問題,咱們能夠爲這兩條路徑編寫一條通用路徑。
這是重寫的代碼:
var app = require("express")(); function checkLogin(){ return false; } function logRequest(){ console.log("New request"); } app.get("/*", function(req, res, next){ logRequest(); next(); }) app.get("/*", function(req, res, next){ if(checkLogin()){ next(); } else{ res("You are not logged in!!!"); } }) app.get("/dashboard", function(req, res, next){ res.send("This is the dashboard page"); }); app.get("/profile", function(req, res, next){ res.send("This is the dashboard page"); }); app.listen(8080);
這裏的代碼看起來更清晰,更易於維護和更新。這裏將前兩個定義的路由處理程序稱爲中間件,由於它們不處理請求,而是負責預處理請求。
Express爲咱們提供了app.use()
方法,該方法專門用於定義中間件。 app.use()
方法可能看起來與app.all()
相似,但它們之間存在不少差別,這使得app.use()
很是適合於聲明中間件。讓咱們看看app.use()
方法是如何工做的:
app.use()
和 app.all()
的不一樣:app.use()
只須要一個回調,而app.all()
能夠進行屢次回調。
app.use()
只查看url是否以指定路徑開頭,app.all()
匹配完整路徑。
這裏有一個例子來講明:
app.use( "/product" , mymiddleware); // will match /product // will match /product/cool // will match /product/foo app.all( "/product" , handler); // will match /product // won't match /product/cool <-- important // won't match /product/foo <-- important app.all( "/product/*" , handler); // won't match /product <-- Important // will match /product/cool // will match /product/foo
中間件內的next()
調用下一個中間件或路由處理程序,具體取決於接下來聲明的那個。可是路由處理程序中的next()
僅調用下一個路由處理程序。若是接下來有中間件,則跳過它。所以,必須在全部路由處理程序以前聲明中間件。
這裏有一個例子來講明:
var express = require('express'); var app = express(); app.use(function frontControllerMiddlewareExecuted(req, res, next){ console.log('(1) this frontControllerMiddlewareExecuted is executed'); next(); }); app.all('*', function(req, res, next){ console.log('(2) route middleware for all method and path pattern "*", executed first and can do stuff before going next'); next(); }); app.all('/hello', function(req, res, next){ console.log('(3) route middleware for all method and path pattern "/hello", executed second and can do stuff before going next'); next(); }); app.use(function frontControllerMiddlewareNotExecuted(req, res, next){ console.log('(4) this frontControllerMiddlewareNotExecuted is not executed'); next(); }); app.get('/hello', function(req, res){ console.log('(5) route middleware for method GET and path patter "/hello", executed last and I do my stuff sending response'); res.send('Hello World'); }); app.listen(80);
如今咱們看到了app.use()
方法的惟一性以及它用於聲明中間件的緣由。
讓咱們重寫咱們的示例站點代碼:
var app = require("express")(); function checkLogin(){ return false; } function logRequest(){ console.log("New request"); } app.use(function(req, res, next){ logRequest(); next(); }) app.use(function(req, res, next){ if(checkLogin()){ next(); } else{ res.send("You are not logged in!!!"); } }) app.get("/dashboard", function(req, res, next){ res.send("This is the dashboard page"); }); app.get("/profile", function(req, res, next){ res.send("This is the dashboard page"); }); app.listen(8080);