---
# System prepended metadata

title: 面試系列文 - 技術面試考題
tags: [面試大哉問]

---

# 面試系列文 - 技術面試考題

## 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: `面試大哉問`



