2017-08-28 65 views
0

我將從一些上下文開始: 我有一個RESTful API服務器,其中包含用於管理用戶的路由;例如是否可以重新指定req.params?

PUT .../users/:id/profile

由於我們的認證流程的一部分,我們驗證用戶的身份,並與我們的IDP檢索到的ID相符的網址比較ID。

我想要做的是實現'我'替換方法;用戶不需要在url中提供他們的id,而是可以簡單地提供'me',而id將根據其身份驗證從IDP中檢索到的id重新分配。我見過Google爲他們的一些API做這件事。例如。 .../users/me/profile

到目前爲止,我一直在嘗試一個簡單的替換假設修改req.params將向前傳播:這是沒有工作,所以

req.params.id = req.params.id === 'me' 
    ? session.id 
    : req.params.id 

我做了一些閱讀了上它顯然req.params獲取與每個中間件函數(當調用.use()時),所以重新分配req.params.id不會傳播整個應用程序,如我所希望的。

目前我們所有的業務邏輯都從req.params中提取id,所以我想知道是否有辦法讓上述行爲能夠避免重構我的所有業務邏輯?

據我所知,req.params是通過解析url來構建的;所以將修改網址是一個選項?用id代替'我';所以req.params是按照預期填充的?如果是這樣,這怎麼能實現呢?或者,如果你有更好的選擇讓上面的'我'替換行爲起作用,那麼我全部都是耳朵!

+0

...如果用戶的ID沒有在URL中提供,應該在其他地方提供。否則,您的RESTful應用程序如何知道用戶的ID? – blewherself

+0

是的,我們可以從認證流程中檢索到id;然而問題是我所有的邏輯檢查id的req.params.id。我正在嘗試這樣做,將身份驗證流中收到的ID注入req.params.id。 – Mitch

+0

明白了...然後你試圖分配'req.params.id'應該可以工作。剛剛測試過,一切都很好,即你可以指定'req.params.id'任何你想要的。你有沒有嘗試爲/ users/me/profile創建新路線? – blewherself

回答

1

全球中間件(您添加使用app.use()router.use())通常甚至不知道任何途徑處理程序聲明的參數,所以req.params平時甚至不填充。

一個解決辦法是「內聯」的修改中間件:

app.put('/users/:id/profile', middleware, ...) 

但這需要重寫所有的路由執行。

正如你已經正確地指出,你可以修改URL:

app.use(function(req, res, next) { 
    if (req.url === '/users/me/profile') { 
    req.url = '/users/1234/profile'; 
    } 
    next(); 
}); 

app.put('/users/:id/profile', ...) 

不需要爲每個URL專門匹配的,可以執行字符串匹配,或使用所有的URL列表可能包含:id參數(因此可能包含me標識符)。

我只是意識到,這應該(使用req.param())工作:

router.param('id', function(req, res, next, id) { 
    if (id === 'me') { 
    req.params.id = '1234'; 
    } 
    next(); 
}); 

這應該被添加到直接申報參數,無論是在路由處理程序,或在安裝點的路由器。

的迴旋例如:

let childRouter = express.Router({ mergeParams : true }); 

childRouter.put('/profile', ...); 

let parentRouter = express.Router({ mergeParams : true }); 

parentRouter.use('/:id', childRouter); 

parentRouter.param('id', function(req, res, next, id) { 
    if (id === 'me') { 
    req.params.id = '1234'; 
    } 
    next(); 
}); 

app.use('/users', parentRouter); 

因爲parentRouter聲明瞭一個掛載點/:id,它應該得到的解析功能。

+0

對不起,應該多澄清一點;是的,我正在使用像你提到的路由處理程序。但是,我有路由器路由到路由器。我有一個路由器/ users /:id,哪個路由器到另一個尋找/ profile的路由器等。因此req.url在那一點上只顯示/ profile。我嘗試修改originalUrl,但它似乎並沒有工作... – Mitch

+0

@Mitch看到我的編輯,有一種可能更強大的重寫方法。 – robertklep

+0

今天做了一些測試,並且req.param()方法像魅力一樣工作。非常感謝你!不知道我完全理解爲什麼在req.param()中設置req.params.id的原理,但不在其他中間件中。 – Mitch