當我們在開發一個完整的應用程式時,不管是 App 或者是 Web,通常會需要拿著 Token 去問 API,然後才能拿回想要的資料。在這個過程中,無可避免的是,Token 會有失效的時候,此時我們會再去跟 API 要一個新的 Token,然後才打 API。
https://dartpad.dev/?id=5d1c608cb191a595c22c17abf82dcb27
在上面這段程式碼中,我們可以發現 get 方法中,不僅處理了 Token 的更新,也處理了 Response 的解碼,兩份工作被同時塞在小小的 get 方法中。我們可以透過抽取方法來解決,讓 get 方法只負責控制流程,把工作交給其他方法。
https://dartpad.dev/?id=d2f993fbb457329db1d410e5215395f9
也可以使用昨天的文章中提到的裝飾者模式,將 Token 更新的職責放到 TokenDecorator 中,讓 TokenDecorator 去負責 Token 的維護,而 HttpProviderImpl 就能專注在呼叫 API 的工作上。
https://dartpad.dev/?id=de4e8caf5686c83d084eae77c98499c8
除了自己實作裝飾者模式之外,許多呼叫 Web API 的相關套件,都有提供類似的功能,讓我們不必重造輪子。
當今天大家使用 http 套件作為呼叫 Web API 的選擇時,我們可以再加上 http_interceptor,為 http 套件外掛上 interceptor 的功能。
https://dartpad.dev/?id=0f5258241320409a0a3b52605288fbdd
當今天任何使用端發出任何 Request 時,都會走近 interceptRequest 方法,此時我們有機會檢查 Token 是否過期,並在適當時機更新 Token,然後程式就會穿過 interceptor 呼叫 API。
相比於自己實現裝飾者模式,使用套件的 Interceptor 功能,能讓我們有機會處理每個 Request 的 header。在上面的程式碼中,我們也可以直接在 Interceptor 把 token 放進 header 中,這樣一來 HttpProvider 也可以避免自已處理 token,讓職責分工更明確。
https://dartpad.dev/?id=0f5258241320409a0a3b52605288fbdd
使用 Interceptor,我們不只能處理 Token,我們也能處理各式各樣的通用邏輯,例如:Logging 或者是 Caching。將不同的職責分配到不同的 Interceptor 也是實現 AOP 的一種方式。
在開發 Flutter 時,除了可以使用 http 來呼叫 Web API 之外,還有 dio 套件也是熱門選項之一。相比於 http 套件,dio 套件本身就自帶有 interceptor 的功能。我們修改一下上面的例子,再看一下程式碼,就會發現他們其實十分相似。
https://dartpad.dev/?id=c15e7eb118a20cd06499adc10dfc8a5d
大多時候,客端程式或多或少,都會需要呼叫 Web API 來取得一些後端資料。我們也常常需要使用 Token 來向後端證明自己合法的使用者,在使用 Token 的過程中,利用裝飾者模式或者 Interceptor 將 Token 管理的職責從實際呼叫 API 的地方分離,除了能讓程式碼職責更明確之外,也讓其符合開放封閉原則。