# 面試系列文 - 技術面試考題
## Router & Middleware
下方是一組路由設定檔,讓我們用 KEVIN / JOHN / JIMMY / MARY 來代稱四組設定。
```
const express = require('express')
const app = express()
// KEVIN
app.use((req, res, next) => {
let name = 'Kevin'
req.name = name
next()
})
// JOHN
app.post('/me', (req, res, next) => {
let name = 'John'
req.name = name
next()
})
// JIMMY
app.use('*', (req, res, next) => {
let name = 'Jimmy'
req.name = name
next()
})
// MARY
app.get('/me', (req, res, next) => {
let name = 'Mary'
req.name = name
next()
})
app.use(function(req, res, next) {
res.json({
answer: req.name
})
})
```
請分別回答下列情境中
1. 呼叫 POST /me 時,最下方的 res.json({ answer: req.name }) 會印出什麼?KEVIN / JOHN / JIMMY / MARY 執行了哪幾個?
2. 呼叫 GET /me 時,,最下方的 res.json({ answer: req.name }) 會印出什麼?KEVIN / JOHN / JIMMY / MARY 執行了哪幾個?
3. 呼叫 GET / 時,,最下方的 res.json({ answer: req.name }) 會印出什麼?KEVIN / JOHN / JIMMY / MARY 執行了哪幾個?
承上,請你先查過 Express.js 文件裡對 app.use 和 next() 的說明,然後運用這兩個概念來解釋上題的各區塊是怎麼被觸發的?(app.use 和 next 兩個概念都需要代入)
1. JIMMY,KEVIN / JOHN / JIMMY
2. MARY , KEVIN / JIMMY / MARY
3. JIMMY , KEVIN / JIMMY
### Q16 回答(5)
首先,
1. 程式由上而下依序執行
2. app.use([path,] callback [, callback...]),文件中提到如果沒有設定path,則會預設為"/",對於 app 所有 根目錄 request 皆會執行 middleware
3. 如果呼叫 next() ,則會呼叫下一個middleware的函數
4. app.use('*', ...),對於 app 的所有 request 皆會執行 middleware
> 呼叫 POST /me 時,最下方的 res.json({ answer: req.name }) 會印出什麼?KEVIN / JOHN / JIMMY / MARY 執行了哪幾個?
1. app.use , req.name = 'Kevin' , next()
2. app.post /me , req.name = 'John' , next()
3. app.use , req.name = 'Jimmy' , next()
4. app.use, res.json ,最後印出 Jimmy
> 呼叫 GET /me 時,,最下方的 res.json({ answer: req.name }) 會印出什麼?KEVIN / JOHN / JIMMY / MARY 執行了哪幾個?
1. app.use , req.name = 'Kevin' , next()
2. app.use , req.name = 'Jimmy' , next()
3. app.get /me, req.name = 'Mary' , next()
4. app.use, res.json ,最後印出 Mary
> 呼叫 GET / 時,,最下方的 res.json({ answer: req.name }) 會印出什麼?KEVIN / JOHN / JIMMY / MARY 執行了哪幾個?
1. app.use , req.name = 'Kevin' , next()
2. app.use , req.name = 'Jimmy' , next()
3. app.use, res.json ,最後印出 Mary
### 補充
#### 問題
請問助教,
app.use ("/", ...) : 根目錄下(可能受route資料夾router匯集影響)
app.use ("*", ...),所有路徑 (不受route資料夾影響)
是這樣做區分嗎?
#### 助教回答
"*" (wildcard) 是正則表示式的一個特殊字元,用以表示符合所有字元,如果像是 "a*",則能符合 a1, a/b/c, asia...,這比較像是經過比對後,所有的路由皆符合 * 的比較,因此皆會執行
而 "/" 屬於 express 的判斷機制,當 app.use "/",則皆會執行該 middleware
兩者皆會受到 router 的影響
注意,並非與 route 資料夾有關,而是與 app.use('path', router)有關,像下述內容並沒有另外再切割程式碼到 route 資料夾下,會建立 route 資料夾主要是希望將 router 相關 module 都整理在 route 資料夾下以便於維護查找
```
const app = express()
const routeA = express.Router()
routeA.get(...)
routeA.use(...)
const routeB = express.Router()
routeB.get(...)
routeB.use(...)
app.use('a', routeA)
app.use('b', routeB)
```
---
## JWT
在 JWT 機制中,token 攜帶了哪些資料?為什麼成功登入後,只要 request 攜帶 token,伺服器就能驗證登入使用者?
### 回答(5)
> token 攜帶了哪些資料?
JWT 是一組字串,透過(.)切分成三個為 Base64 編碼的部分:
* Header
* Payload
* Signature
```
// base64(Header) + base64(Payload) + base64(Signature)
// xxxxx.yyyyy.zzzzz
```
* Header
Header 是一個包含定義 Token 種類(type)及雜湊演算法(alg)資訊的 JSON。在此設定 Token 種類為 JWT、產生簽章(signature)要使用的雜湊演算法為 HS256。此 JSON 將被轉換成 Base64 編碼,成為第一個部分:
```
{
"typ": "JWT",
"alg": "HS256",
}
```
* Payload(Claim)
Payload 也是一個 JSON,可以解釋為要壓縮的資料,使用者和相關的資訊都可放置其中。通常會使用 exp 設定 Token 到期的時間、iat 設定 Token 簽發時間。最後再被轉換成 Base64 編碼,成為第二個部分:
```
{
"_id": "<user_id>",
"name": "John",
"exp": 1300819999
}
//建議只放必要且不隱私的資訊,不建議放過多資訊
```
* Signature
Signature會是 Payload 和 Header經過一組密鑰(Secret),加密(序列化)而成的字串。由於密鑰(ex. Secret: THISISSECRET) 並非公開,儲存在伺服端,因此伺服器端在拿到 Token 後,透過解碼,確認資料內容正確未被變更,以驗證對方身份。
```
var payload = { id: user.id }
//(Base64(Header) + "." + Base64(Payload), secretKey)
var token = jwt.sign(payload, 'THISISSECRET')
```
任何人都可以修改 JWT 的內容,但是當他簽發的時候並不知道密碼,所以就會有不對的簽名,伺服端也就不會接受這個錯誤的 JWT。
> 伺服器如何驗證使用者?
伺服端收到客戶端發送的token後,會進行反序列化,先將JWT的 Payload 和 Header 解析後,再和伺服端的Secret序列化後,得出新的Signature,與原本的Signature進行比對。如果相同,則此token有效完成身分認證,回傳200,才可以使用 Payload 的數據;如果不同,則此客戶端可能具有危險,回傳403。
###### tags: `面試大哉問`