從一個舒服的姿勢插入 HttpClient 攔截器技能點

馬甲哥繼續寫一點大前端,閱讀耗時5 minute,行文耗時5 Days
今天我們來了解一下如何攔截axios請求/響應? 這次我們舉一反三,用一個最舒適的姿勢插入這個技能點。

axios是一個基於 promise 的網絡請求庫,可以用於瀏覽器和 node.js;
promise 類似於C#的Task async/await機制,以同步的代碼風格編寫異步代碼;

而axios攔截器就類似於 C# HttpClient自定義message Handler, 給你一個請求/響應在被handler之前做一些自定義動作的機會。

C# 請求/響應攔截器

axios請求/響應攔截器的定位就類似於 C# HttpClient的自定義message handler。

.NET默認的message handler是HttpClientHandler,開發者可以插入自定義的message handler。

用途舉例 ① 插入日誌 ② 插入自定義Header

(1) 更具體的就是System.Net.Http.DelegatingHandler類,開發者重寫SendAsync方法,可以攔截請求/響應, 注入動作。

protected override Task<HttpResponseMessage> SendAsync(
     HttpRequestMessage request, System.Threading.CancellationToken cancellationToken)
}

自定義message handler形成的是pipeline, 肉眼可猜測使用的是責任鏈模式。

(2) 添加自定義message handler

使用HttpCLientFactory.Create方法。

HttpClient client = HttpClientFactory.Create(new MessageHandler1(), new MessageHandler2());

自定義message handler的執行順序,是傳入Create方法的順序,也就是說,上面最後一個handler是最先接觸到響應的。

—- 以上是.NET Framework插入攔截器的用法—-

推及到.NET Core, 因為大量應用了提前配置&&依賴注入,實際由IHttpClientFactory來注入HttpClient。

提前配置HttpClient攔截器的代碼如下:

services.AddHttpClient("bce-request", x =>
                   x.BaseAddress = new Uri(Configuration.GetSection("BCE").GetValue<string>("BaseUrl")))
                .ConfigureHttpMessageHandlerBuilder(_=> new LoggerMessageHandler{...} )   
                .ConfigurePrimaryHttpMessageHandler(_ => new BceAuthClientHandler{...})

有關.NET Core IHttpClientFactory的內幕請看這裡。

axios攔截器

axios一般發起的是ajax請求,我們一般會封裝處理一些通用的請求/響應動作。

碼甲哥就遇到:

(1) 在每次ajax跨域請求時,允許攜帶第三方憑據(cookie、authorization)

(2) 封裝4xx響應碼的處理邏輯

其中就要用到axios的攔截器:

export interface AxiosInterceptorManager<V> {
  use<T = V>(onFulfilled?: (value: V) => T | Promise<T>, onRejected?: (error: any) => any): number;
  eject(id: number): void;
}

仔細圍觀usesdk,支持傳入兩個函數,
表示請求(響應)一旦準備好了/失敗了,你可以注入的動作。

精簡代碼如下:

import axios from 'axios';
import {
    message
  } from 'antd'

const service = axios.create({
    baseURL: process.env.REACT_APP_APIBASEURL, 
    timeout: 5000
})
// 添加請求攔截器
service.interceptors.request.use((reqconfig) => {
    reqconfig.withCredentials = true;
    return reqconfig;
}, (error) => {
    return Promise.reject(error);
});

// 添加響應攔截器
service.interceptors.response.use((response) => {
    return response;
}, (error) => {
    if (error.response && error.response.status === 401) {
        message.error("無權限操作,請聯繫tvs運維.")
    }
    return Promise.reject(error);
});

以上對於前端老鳥不值一提,但是上述攔截動作對於把握全棧web開發必不可少。
本文另作為 前端快閃四: 如何攔截axios請求/響應?

旁白

當你的基礎知識體系形成了知識樹,你會發現各種語言的對於某個技能點的實現都是同一種套路,差別只在於場景。

這就會給你一個感覺,你目前雖然不知道怎麼寫, 但是你知道它就在那裡,它在那裡,就在那裡……