2012-10-30 27 views
77

一直在試圖找到next()方法所做的很好的描述。在Express文檔中,它表示可以使用next('route')跳轉到該路由並跳過所有路由,但有時next被調用時沒有參數。任何人都知道一個很好的教程等介紹next函數?表達下一個功能,它真的是什麼?

回答

105

next()沒有參數說「只是開玩笑,我實際上不想處理這個」。它回到並嘗試找到匹配的下一條路線。

這很有用,比方說,如果你想擁有某種頁面管理器和url slugs,以及許多其他的東西,但這裏有一個例子。

app.get('/:pageslug', function(req, res, next){ 
    var page = db.findPage(req.params.pageslug); 
    if (page) { 
    res.send(page.body); 
    } else { 
    next(); 
    } 
}); 

app.get('/other_routes', function() { 
    //... 
}); 

構成的代碼應該檢查數據庫中是否有一個具有某個id slug的頁面。如果它發現一個渲染它!如果它找不到一個,則忽略此路由處理程序並檢查其他路由處理程序。

所以next()沒有參數允許假裝你沒有處理路線,所以別的東西可以拿起它。


或與app.all('*')匹配的計數器。這可以讓你執行一些共享的設置代碼,然後轉到其他路線去做更具體的事情。

app.all('*', function(req, res, next){ 
    myHitCounter.count += 1; 
    next(); 
}); 

app.get('/other_routes', function() { 
    //... 
}); 
+0

很好的答案! 我也看到了其他一些用法,例如下一個(err)和下一個('route')。你現在的目的是什麼,你想傳播一個錯誤,什麼時候你想跳到某個路線? –

+7

@AndreasSelenwall'next('route')'特定於['app.VERB()'](http://expressjs.com/api.html#app.VERB),當路由有多個回調函數「*繞過剩餘的路由回調*」'next(err)'用於跳轉到任何「[錯誤中間件](http://stackoverflow.com/a/7151775/15031)」('E'來自職位)。 –

+2

Upvoted。只是爲了這句話:「只是在開玩笑,我實際上並不想處理這件事」,你讓我明白了我在找什麼。我看到很多類似的問題,並在一個短語中找到解決方案。 –

102

在大多數框架中,您會收到一個請求並要返回響應。由於Node.js的異步特性,如果你正在做非平凡的事情,你會遇到嵌套回調的問題。爲了避免這種情況發生,Connect.js(v4.0之前,Express.js是connect.js之上的一個圖層)有一些稱爲中間件的東西,它是具有2,3或4個參數的函數。

function (<err>, req, res, next) {} 

您的Express.js應用程序是這些函數的堆棧。

enter image description here

路由器是特殊的,它的中間件,可以讓你執行一個或多箇中間件一定URL。所以它是一個堆棧內的堆棧。

那麼接下來會做什麼?簡單來說,它會告訴你的應用程序運行下一個中間件。但是當你傳遞給下一個時會發生什麼? Express將中止當前堆棧並運行所有具有4個參數的中間件。

function (err, req, res, next) {} 

該中間件用於處理任何錯誤。我想做到以下幾點:

next({ type: 'database', error: 'datacenter blew up' }); 

有了這個錯誤,我可能會告訴用戶出了問題,登錄真正的錯誤。

function (err, req, res, next) { 
    if (err.type === 'database') { 
    res.send('Something went wrong user'); 
    console.log(err.error); 
    } 
}; 

如果你的圖片應用Express.js作爲堆棧你大概就能解決很多古怪自己。例如,當您在路由器後添加Cookie中間件時,您的路由不會使用Cookie。

+7

優秀的答案。 –

+3

你會在哪裏存儲這個匿名日誌功能? – dennismonsewicz

5

next()不帶參數調用框架中的下一個路由處理程序。

+0

或下一個中間件。 – robertklep

18

恕我直言,這個問題接受的答案是不是真的準確。正如其他人所說的,它確實是在控制鏈中的下一個處理程序何時運行。但是我想提供更多的代碼來使它更加具體。假設你有這個簡單的表達應用:

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

app.get('/user/:id', function (req, res, next) { 
    console.log('before request handler'); 
    next(); 
}); 

app.get('/user/:id', function (req, res, next) { 
    console.log('handling request'); 
    res.sendStatus(200); 
    next(); 
}); 

app.get('/user/:id', function (req, res, next) { 
    console.log('after request handler'); 
    next(); 
}); 

app.listen(3000, function() { 
    console.log('Example app listening on port 3000!') 
}); 

如果你

curl http://localhost:3000/user/123 

,你會看到這樣的打印到控制檯:

before request handler 
handling request 
after request handler 

現在,如果你註釋掉調用next()像這樣的中間處理器:

app.get('/user/:id', function (req, res, next) { 
    console.log('handling request'); 
    res.sendStatus(200); 
    //next(); 
}); 

你會看到這在控制檯上:

before request handler 
handling request 

注意,最後一個處理程序(即打印after request handler一)不運行。那是因爲你不再用快遞來運行下一個處理程序。

因此,如果您的「主」處理程序(返回200的處理程序)成功或不成功,如果您希望剩下的中間件運行,則必須調用next()

什麼時候這會派上用場?假設您想記錄所有進入某個數據庫的請求,而不管請求是否成功。

app.get('/user/:id', function (req, res, next) { 
    try { 
     // ... 
    } 
    catch (ex) { 
     // ... 
    } 
    finally { 
     // go to the next handler regardless of what happened in this one 
     next(); 
    } 
}); 

app.get('/user/:id', function (req, res, next) { 
    logToDatabase(req); 
    next(); 
}); 

如果你想第二個處理器來運行,你必須調用next()第一處理器。

請記住,節點是異步的,所以它不知道第一個處理程序的回調何時完成。你必須通過致電next()來告訴它。

+0

這是一個非常明確的解釋。謝謝。 – swdon

相關問題