最近筆者在專案中串接 Spotify 提供的 Web API,利用官方推薦的 PKCE flow 來做使用者驗證。在該驗證流程中,每次向 Spotify 請求 token 時,都會拿到一組 access token 和 refresh token,然後在 access token 過期時,程式就需要透過 refresh token 向 Spotify 的 API 再請求新的一組 token。
在 概念驗證 (proof of concept,POC) 階段,筆者僅串接 Get New Releases API,因此首頁載入後會經過以下流程:
從上面的流程不難想像,如果沒有對 request 或 response 做任何管控,可能會有以下問題:
因此筆者需要一種機制檢查 access token 是否過期,以及 Get New Release 在 token 過期後,需要刷新 token 並重新請求 New Release 資源。
雖然可以直接對 fetch API 的邏輯進行擴充,但看到 axios 有攔截器 (interceptor) 機制,可以對 request 和 response 過程做更精準的操控後,筆者決定使用 axios 來實作。
Axios 是一個基於 XMLHttpRequest 和 Promise,用來處理 http 請求的套件,相較於 fetch API,它具有以下亮點,因此廣受網頁開發者的喜愛:
transformRequest
和 transformResponse
將送出或取回的資料轉型,還可設定 api endpoint 的 baseURL。const instance = axios.create({
baseURL: "https://some-domain.com/api/",
timeout: 1000,
headers: { "X-Custom-Header": "foobar" },
});
instance 這個物件就可以替代原本用來發 request 的 axios 物件,並帶有以上這些預設的 config。
axios.instance 提供 interceptor.use() 方法,可以在 request 發出之前、response 的 Promise resolve 之前做一些額外的操作,筆者便利用它來做 token 時效的檢查以及 token 失效後刷新 token 的功能。
建立 axios instance
const instance = axios.create({
baseURL: BASE_ENDPOINT,
method: "POST",
headers: { "Content-Type": "application/x-www-form-urlencoded" },
});
添加 request interceptor,在每次請求 token 時,用 localStorage 裡面存的 timestamp 檢查 access token 是否過期,若否則不請求 token,若是則用 localStorage 裡的 refresh token 重新請求 access token。
添加 response interceptor,在每次請求 New Releases 得到 response 後,檢查是否有 401 錯誤,若是則重新請求 access token,並重新請求 New Releases
後來筆者在網路上發現,其實用一個 wrapper function 把 fetch API 包裝起來,也可以做到攔截 request/response 的效果,但我認為 axios 攔截器的好處在於,它將請求前後的邏輯和請求本身整合在一起,讓請求的邏輯變得更完整且可復用,若不介意需要額外安裝套件的話,axios 攔截器不失為一個好選擇。