前言
使用react框架中經常使用到umi來搭建管理我們的專案,其中涉及到請求的模塊,umi自身提供了 umi-request 庫 方便了我們做網路請求, umi-request的官方檔案可見其githubREADME.MD檔案, 大部分功能都在readme中查詢,大部分功能已經將的很清楚了,單獨拿出 middleware和 interceptors 這兩個概念講一下,
為什么是 middleware和 interceptors
在使用umi-request的程序中最常見的需求是,對網路請求的攔截,在請求前或請求后做一些事情,例如URL添加前綴,過濾無效引數,上報介面錯誤,頁面錯誤統一處理,單獨介面定制化處理等..., middleware (中間件) 和 interceptors (攔截器) 以及 errorHandler 是實作此類需求繞不過去的概念,雖然他們都能影響請求和回傳結果,但是哪種場景下使用哪個函式?需要了解其實如何實作的,以及代碼的前后執行邏輯,
核心代碼
// onion/index.js
execute(params = null) {
const fn = compose([
...this.middlewares,
...this.defaultMiddlewares,
...Onion.globalMiddlewares,
...Onion.coreMiddlewares,
]);
return fn(params);
}
- middlewares 和 interceptors.response 的關系 偽代碼就是 middleware(ctx) ctx 物件中包含responseInterceptors函式 ,也就是說responseInterceptors函式 會作為 middleware的引數使用
- compose函式會把middlewares中的函式按照順序串聯成一個可以遞回呼叫的函式,fn(params) 會把這個遞回呼叫函式執行掉
關于middleware
-
使用
- request.use(fn) // 默認加載到 onion實體上
- request.use(fn, { defaultInstance: true })
- request.use(fn, { global: true })
- request.use(fn, { core: true })
-
呼叫邏輯:extend(configObj)生成request實體,request初始化中生成一個Core實體,Core實體初始化中使用一個Onion實體, 我們呼叫的request.use實際上是Onion實體上的use方法
-
use方法的第二個引數是可選引數,根據這個配置決定這個middleware加載到哪一層,呼叫的順序也是不一樣的,具體查看官方給的示例,
-
request.use(fn) 默認加載到 onion實體上,執行的時候會首先進入這一類的middleware
-
request.use(fn, { defaultInstance: true }) 官方給出的描述是 “默認實體中間件,供開發者使用”,此類middleware還是會加載到Onion實體上,默認Core實體中給出了"[]"的配置
-
request.use(fn, { global: true }) ,全域中間件中本身就內置了三個函式
[simplePost, simpleGet, parseResponseMiddleware]- simplePost實作了默認請求頭設定,
'Content-Type': 'application/json;charset=UTF-8'自動配置form型別的請求頭; 功能在next()前; - simpleGet實作了get請求使用params引數自動序列化;功能在next()前;
- parseResponseMiddleware實作了Http Status Code 的判斷
copy.status >= 200 && copy.status < 300之外的code會作為錯誤被拋出; 功能在next()之后; - 自己加入的middleware會放在這三個后,執行的順序用洋蔥模型理解一下就是“后進先出”
- simplePost實作了默認請求頭設定,
-
request.use(fn, { core: true }), 核心中間件內置了一個函式
[fetchMiddleware], 也是umi-request真正發起介面呼叫的地方,使用的是瀏覽器原生的fetch物件 -
fetchMiddleware 實作了瀏覽器兼容性判斷,快取資料獲取,超時邏輯,取消請求功能;在原生fetch請求回的第一時間,就進入了responseInterceptors的函式,所以interceptors.response.use進來的攔截器函式是第一批接觸到真正fetch回傳的response物件的函式,此時的response 物件是沒有經過包裝的原生fetch請求回來的物件,物件上常用的屬性有
status,statusText,ok等屬性
關于Interceptors 攔截器
- Interceptor分為兩部分,請求前的攔截,請求后的攔截
- 請求前的攔截,是在進入洋蔥模型之前執行的函式,也就是說interceptors.request.use中的函式,會比任何middleware中的函式執行的早
return new Promise((resolve, reject) => {
this.dealRequestInterceptors(obj) // 在此處完成了interceptors.request.use中函式的執行
.then(() => onion.execute(obj))
.then(() => {
resolve(obj.res);
})
.catch(error => {
...
});
- 請求前的攔截可以操作的屬性或物件只有 url 和 options 兩個,只對這樣個物件進行操作
- 請求后的攔截是在 onion洋蔥模型的 最深處 執行,也就是上面提到的fetchMiddleware在獲取到fetch response 物件的第一時間會交給interceptors.response.use中的攔截函式處理
errorHandler
- errorHandler執行的時機最晚,在各種攔截器各種中間件執行完成以后,這個時候如果捕獲到了例外才執行,
- 默認的errorHandler的邏輯是,如果有配置errorHandler,errorHandler墊底,如果沒有配置errorhandle會直接拋出例外;
- 單個請求option的 errorHandler 會覆寫 extend(config) 中的 config.errorHandler, 這屬于option覆寫的邏輯,不展開細講,有不懂的可以看一下官方檔案或原始碼
middleware 和 interceptor 可以拿到的引數
- 先看下ctx 物件
const obj = {
req: { url, options },
res: null,
cache: this.mapCache,
responseInterceptors: [...Core.responseInterceptors, ...this.instanceResponseInterceptors],
};
- middleware(ctx, next) 函式 next 表示進入到下一層(里面一層),next 前的邏輯和next后的邏輯,按照洋蔥的進出的定義來理解,ctx 就是上述ctx物件
- requestIntercetor的引數是 url 和options配置
- responseIntercetor的引數是 原生的fetch產生的res物件
最后結合官方的示例理解一下執行順序
request.use(async (ctx, next) => {
console.log('instanceA1');
await next();
console.log('instanceA2');
});
request.use(async (ctx, next) => {
console.log('instanceB1');
await next();
console.log('instanceB2');
});
request.use(
async (ctx, next) => {
console.log('globalA1');
await next();
console.log('globalA2');
},
{ global: true }
);
request.use(
async (ctx, next) => {
console.log('coreA1');
await next();
console.log('coreA2');
},
{ core: true }
);
// 執行順序是
instanceA1 -> instanceB1 -> globalA1 -> coreA1 -> coreA2 -> globalA2 -> instanceB2 -> instanceA2
再加上我們上面的理解可以理解成這樣
// 看一下fetch的位置
instanceA1 -> instanceB1 -> globalA1 -> coreA1 -> fetch() -> coreA2 -> globalA2 -> instanceB2 -> instanceA2
// 看一下內置中間件 + 攔截器的執行順序
requestInterceptor -> 自定義middleware -> simplePost-> simpleGet-> parseResponseMiddleware -> fetch -> responseInterceptor
自定義middleware <- simplePost <- simpleGet <- parseResponseMiddleware <-
寫在最后
雖然沒有具體規定哪個函式應該做什么,但是知道執行順序以后,就很方便我們拓展了
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/227123.html
標籤:其他
上一篇:tarBar沒有出現
下一篇:前端-JavaScript
