nodejs開發 express路由與中間件

来源:http://www.cnblogs.com/zapple/archive/2016/07/18/5683016.html
-Advertisement-
Play Games

路由 通常HTTP URL的格式是這樣的: http://host[:port][path] http表示協議。 host表示主機。 port為埠,可選欄位,不提供時預設為80。 path指定請求資源的URI(Uniform Resource Identifier,統一資源定位符),如果URL中沒 ...


路由

通常HTTP URL的格式是這樣的:

http://host[:port][path]

http表示協議。

host表示主機。

port為埠,可選欄位,不提供時預設為80。

path指定請求資源的URI(Uniform Resource Identifier,統一資源定位符),如果URL中沒有給出path,一般會預設成“/”(通常由瀏覽器或其它HTTP客戶端完成補充上)。

所謂路由,就是如何處理HTTP請求中的路徑部分。比如“http://xxx.com/users/profile”這個URL,路由將決定怎麼處理/users/profile這個路徑。

來回顧我們在Node.js開發入門——Express安裝與使用中提供的express版本的HelloWorld代碼:

var express = require('express');
var app = express();

app.get('/', function (req, res) {
  res.send('Hello World!');
});

app.listen(8000, function () {
  console.log('Hello World is listening at port 8000');
});

上面代碼里的app.get()調用,實際上就為我們的網站添加了一條路由,指定“/”這個路徑由get的第二個參數所代表的函數來處理。

express對象可以針對常見的HTTP方法指定路由,使用下麵的方法:

app.METHOD(path, callback [, callback ...])

METHOD可以是GET、POST等HTTP方法的小寫,例如app.get,app.post。path部分呢,既可以是字元串字面量,也可以是正則表達式。最簡單的例子,把前面代碼里的app.get()調用的一個參數’/’修改為’*’,含義就不一樣。改動之前,只有訪問“http://localhost:8000”或“http://localhost:8000/”這種形式的訪問才會返回“Hello World!”,而改之後呢,像“http://localhost:8000/xxx/yyyy.zz”這種訪問也會返回“Hello World!”。

使用express構建Web伺服器時,很重要的一部分工作就是決定怎麼響應針對某個路徑的請求,也即路由處理。

最直接的路由配置方法,就是調用app.get()、app.post()一條一條的配置,不過對於需要處理大量路由的網站來講,這會搞出人命來的。所以呢,我們實際開發中需要結合路由參數(query string、正則表達式、自定義的參數、post參數)來減小工作量提高可維護性。更詳細的信息,參考http://expressjs.com/guide/routing.html

中間件

Express里有個中間件(middleware)的概念。所謂中間件,就是在收到請求後和發送響應之前這個階段執行的一些函數。

要在一條路由的處理鏈上插入中間件,可以使用express對象的use方法。該方法原型如下:

app.use([path,] function [, function...])

當app.use沒有提供path參數時,路徑預設為“/”。當你為某個路徑安裝了中間件,則當以該路徑為基礎的路徑被訪問時,都會應用該中間件。比如你為“/abcd”設置了中間件,那麼“/abcd/xxx”被訪問時也會應用該中間件。

中間件函數的原型如下:

function (req, res, next)

第一個參數是Request對象req。第二個參數是Response對象res。第三個則是用來驅動中間件調用鏈的函數next,如果你想讓後面的中間件繼續處理請求,就需要調用next方法。

給某個路徑應用中間件函數的典型調用是這樣的:

app.use('/abcd', function (req, res, next) {
  console.log(req.baseUrl);
  next();
})

app.static中間件

Express提供了一個static中間件,可以用來處理網站里的靜態文件的GET請求,可以通過express.static訪問。

express.static的用法如下:

express.static(root, [options])

第一個參數root,是要處理的靜態資源的根目錄,可以是絕對路徑,也可以是相對路徑。第二個可選參數用來指定一些選項,比如maxAge、lastModified等,更多選項的介紹看這裡:http://expressjs.com/guide/using-middleware.html#middleware.built-in

一個典型的express.static應用如下:

var options = {
  dotfiles: 'ignore',
  etag: false,
  extensions: ['htm', 'html'],
  index: false,
  maxAge: '1d',
  redirect: false,
  setHeaders: function (res, path, stat) {
    res.set('x-timestamp', Date.now());
  }
}

app.use(express.static('public', options));

上面這段代碼將當前路徑下的public目錄作為靜態文件,並且為Cache-Control頭部的max-age選項為1天。還有其它一些屬性,請對照express.static的文檔來理解。

使用express創建的HelloExpress項目的app.js文件里有這樣一行代碼:

app.use(express.static(path.join(__dirname, 'public')));

這行代碼將HelloExpress目錄下的public目錄作為靜態文件交給static中間件來處理,對應的HTTP URI為“/”。path是一個Node.js模塊,__dirname是Node.js的全局變數,指向當前運行的js腳本所在的目錄。path.join()則用來拼接目錄。

有了上面的代碼,你就可以在瀏覽器里訪問“http://localhost:3000/stylesheets/style.css”。我們做一點改動,把上面的代碼修改成下麵這樣:

app.use('/static', express.static(path.join(__dirname, 'public')));

上面的代碼呢,針對/static路徑使用static中間件處理public目錄。這時你再用瀏覽器訪問“http://localhost:3000/stylesheets/”就會看到一個404頁面,將地址換成“http://localhost:3000/static/stylesheets/style.css”就可以了。

Router

Express還提供了一個叫做Router的對象,行為很像中間件,你可以把Router直接傳遞給app.use,像使用中間件那樣使用Router。另外你還可以使用router來處理針對GET、POST等的路由,也可以用它來添加中間件,總之你可以將Router看作一個微縮版的app。

下麵的代碼創建一個Router實例:

var router = express.Router([options]);

然後你就可以像使用app一樣使用router(代碼來自http://expressjs.com/4x/api.html#router):

// invoked for any requests passed to this router
router.use(function(req, res, next) {
  // .. some logic here .. like any other middleware
  next();
});

// will handle any request that ends in /events
// depends on where the router is "use()'d"
router.get('/events', function(req, res, next) {
  // ..
});

定義了router後,也可以將其作為中間件傳遞給app.use:

app.use('/events', router);

上面這種用法,會針對URL中的“/events”路徑應用router,你在router對象上配置的各種路由策略和中間件,都會被在合適的時候應用。

路由模塊

express工具創建的應用,有一個routes目錄,下麵保存了應用到網站的Router模塊,index.js和user.js。這兩個模塊基本一樣,我們研究一下index.js。

下麵是index.js的內容:

var express = require('express');
var router = express.Router();

/* GET home page. */
router.get('/', function(req, res, next) {
  res.render('index', { title: 'Express' });
});

module.exports = router;

index.js創建了一個Router實例,然後調用router.get為“/”路徑應用了路由函數。最後呢使用module.exports將Router對象導出。

下麵是app.js里引用到index.js的代碼:

var routes = require('./routes/index');
...
app.use('/', routes);

第一處,require(‘./routes/index’)將其作為模塊使用,這行代碼導入了index.js,並且將index.js導出的router對象保存在變數routes里以供後續使用。註意,上面代碼里的routes就是index.js里的router。

第二處代碼,把routes作為一個中間件,掛載到了“/”路徑上。

模塊

前面分析index.js時看到了module.exports的用法。module.exports用來導出一個Node.js模塊內的對象,調用者使用require載入模塊時,就會獲得導出的對象的實例。

我們的index.js導出了Router對象。app.js使用require(‘./routes/index’)獲取了一個Router實例。

module.exports還有一個輔助用法,即直接使用exports來導出。

exports.signup = function(req, res){
  //some code
}

exports.login = function(req, res){
  //some code
}

上面的代碼(假定在users.js文件里)直接使用exports來導出。當使用exports來導出時,你設置給exports的屬性和方法,實際上都是module.exports的。這個模塊最終導出的是module.exports對象,你使用類似“exports.signup”這種形式設置的方法或屬性,調用方在require後都可以直接使用。

使用users模塊的代碼可能是這樣的:

var express = require('express');
var app = express();
...
var users = require('./routes/users');
app.post('/signup', users.signup);
app.post('/login', users.login);
...

 

 

 1.  什麼是router路徑,什麼是middleware?

 

我們輸入www.baidu.com 來訪問百度的主頁,瀏覽器會自動轉換為 http://www.baidu.com:80/(省略一些參數)。 http://代表我們同伺服器連接使用的是http協議,www.baidu.com 代表的是伺服器的主機地址,會被我們的pc通過DNS解析為IP地址。80是預設的應用層埠。/ 即為我們訪問的伺服器(www.baidu.com)的路徑,伺服器要對我們訪問的這個路徑做出響應,採取一定的動作。我們可以把這一過程看做一個路由。

 訪問的路徑‘/’即為router的路徑,伺服器採取的動作即為middleware,即為一個個特殊的函數。

 

  2. router路徑

   www.baidu.com/test: 路徑為 /test

      www.baidu.com/test?name=1&number=2: 路徑同樣為/test, ?後面會被伺服器理解傳給路徑的參數。

   3. Middleware 

複製代碼
An Express application is essentially a stack of middleware which are executed serially.(express應用其實就是由一系列順序執行的Middleware組成。)
A middleware is a function with access to the request object (req), the response object (res), and the next middleware in line in the request-response cycle of an Express application. It is commonly denoted by a variable named next. Each middleware has the capacity to execute any code, make changes to the request and the reponse object, end the request-response cycle, and call the next middleware in the stack. Since middleware are execute serially, their order of inclusion is important.(中間件其實就是一個訪問express應用串入的req,res,nex參數的函數,這個函數可以訪問任何通過req,res傳入的資源。)
If the current middleware is not ending the request-response cycle, it is important to call next() to pass on the control to the next middleware, else the request will be left hanging.(如果當前中間件沒有完成對網頁的res響應 ,還可以通過next把router 留給下一個middleware繼續執行)
With an optional mount path, middleware can be loaded at the application level or at the router level. Also, a series of middleware functions can be loaded together, creating a sub-stack of middleware system at a mount point.
複製代碼

 

  路由的產生是通過HTTP的各種方法(GET, POST)產生的,Middleware可以跟router路徑跟特定的HTTP方法綁定,也可以跟所有的方法綁定。

  3.1 通過express應用的use(all),把Middleware同router路徑上的所有HTTP方法綁定:

1 app.use(function (req, res, next) {
2   console.log('Time: %d', Date.now());
3   next();
4 })

 

  3.2 通過express應用的http.verb,把Middleware同router路徑上的特定的HTTP方法綁定:

複製代碼
1 app.get('/', function(req, res){
2   res.send('hello world');
3 });
4 
5 
6 app.post('/', function(req, res){
7   res.send('hello world');
8 });
複製代碼

 

 

  4.  Express的Router對象

  當express實例的路由越來越多的時候,最好把路由分類獨立出去,express的實例(app) 能更好的處理其他邏輯流程。Express的Router對象是一個簡化的 app實例,只具有路由相關的功能,包括use, http verbs等等。最後這個Router再通過app的use掛載到app的相關路徑下。

 

複製代碼
 1 var express = require('express');
 2 var app = express();
 3 var router = express.Router();
 4 
 5 // simple logger for this router's requests
 6 // all requests to this router will first hit this middleware
 7 router.use(function(req, res, next) {
 8   console.log('%s %s %s', req.method, req.url, req.path);
 9   next();
10 });
11 
12 // this will only be invoked if the path ends in /bar
13 router.use('/bar', function(req, res, next) {
14   // ... maybe some additional /bar logging ...
15   next();
16 });
17 
18 // always invoked
19 router.use(function(req, res, next) {
20   res.send('Hello World');
21 });
22 
23 app.use('/foo', router);
24 
25 app.listen(3000);
複製代碼

 

 

 

  router的路由必須通過app.use和app.verbs 掛載到app上才能被響應。所以上述代碼,只有在app捕捉到 /foo路徑上的路由時,才能router中定義的路由,雖然router中有針對 '/' 的路由,但是被app中的路由給覆蓋了。

 

 

附:app.verbs和app.use的路由路徑區別:

先看一段測試代碼:

var express = require('express');

var app = express();
var router = express.Router();

app.get('/', function(req, res){
     console.log('test1');
});

app.use('/', function(req, res){
     console.log('test2');
});

router.get('/', function(req, res){
     console.log('test3');
});

app.listen(4000);

 

輸入url: localhost:4000

輸出結果:test1   輸入url: localhost:4000/hello 輸出結果:test2     結論:app.get掛載‘/’的路由只響應跟'/'精確匹配的GET請求。 而app.use掛載的'/'的路由響應所有以'/' 為起始路由的路由,且不限制HTTP訪問的方法。以下說明:Mounting a middleware at a path will cause the middleware function to be executed whenever the base of the requested path matches the path.  
1 app.use([path], [function...], function)
2 Mount the middleware function(s) at the path. If path is not specified, it defaults to "/".
3 
4 Mounting a middleware at a path will cause the middleware function to be executed whenever the base of the requested path matches the path.

 

 

 

 

摘自CSDN:Node.js開發入門—Express里的路由和中間件

摘自博客園:express 框架之 路由與中間件

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 線上實例 實例演示 使用方法 複製 複製 下載 ...
  • 本文標題的這副圖片,是用Phosotshop製作的。但是,在搜索引擎中你卻無法搜索到它,搜索引擎還沒有強大到能夠識別圖片裡面的文字。並且由於圖片的體積不算太小,可能網速慢的網友在瀏覽的時候不得不耐心的等待圖片的刷新。那麼,有沒有一種新的方法可以避免這些缺點呢? 有的,HTML5和CSS3就可以滿足你 ...
  • 別人的代碼,拿過來調,發現修改功能都不能用,修改時通過ajax發json獲取數據的,看chrome開發者工具發現有發送數據,也有返回值; 發起請求並獲取數據,發現回調函數不執行! php返回數據代碼: 返回的數據在瀏覽器里看上去也很正常: {"data":{"id":"1","name":"admi ...
  • 我們先來看一道題目 1 2 3 4 var write = document.write; write("hello"); //1.以上代碼有什麼問題 //2.正確操作是怎樣的 1 2 3 4 var write = document.write; write("hello"); //1.以上代碼有 ...
  • 摘要: 之前項目用過Less,現在負責的項目也要使用,所以就總結下Less,也方便以後查看。本文主要是講瀏覽器端如何使用Less。 簡介: LESS是一種由Alexis Sellier設計的動態層疊樣式表語言。LESS 是開源的,其第一個版本由Ruby寫成,但在後續的版本當中,Ruby逐漸被替換為J ...
  • 所謂的作用域,可以簡單理解為一個可以讀、寫的範圍(區域),有些js經驗的同學可能會說:"js沒有塊級作用域",js除了全局作用域外,只有函數可以創建作用域。作用域的一個好處就是可以隔離變數。 我們通過一些例子來幫助我們理解js中的作用域。 如果對作用域一點不瞭解的同學可能會說 alert的是1或者報 ...
  • 水平居中 若為行內元素,對其父元素用text-align:center即可; 若為塊元素(無浮動),則一般有兩種方法可實現對其的水平居中,一為margin:0 auto;二為通過css計算函數calc; 垂直居中 若為行內元素,一般對其父元素用line-height:{height}即可,若為圖片元 ...
  • 第0章 關於本書 1, 本書要用到一個工具函數————$$(),它可以讓我們更容易獲取和遍歷所有匹配特定css選擇符的dom元素: 2, 以下實現一個效果: 3, 檢查屬性是否存在: 檢測多個屬性: 檢測某個具體的屬性值是否支持: 第1章 前言 1, 不用-ms-border-radius和-o-b ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...