爲何要給fetch增長攔截器?瀏覽器提供的fetch方法不夠用嗎?ios
是的。原生fetch確實不夠用。程序員
在項目中,若是想要在全部的網絡請求以前往header中加入權限信息(好比:authorization=xxxx)。用原生fetch的話,你只能在每一個fetch請求的時候,header配置中寫上authorization=xxxx。或者在請求結果返回來以後,對響應結果作一些特殊處理,在原生fetch中,咱們只能在每一個請求的結果回來以後,都寫一遍特殊處理。這樣作起來一點都不優雅,一點都不高級。相信每個程序員都是一個懶人,能用少許代碼實現出更優雅,更健壯程序的話,絕對不用大量代碼實現一個很脆弱的程序。ajax
用過axios的人,都知道axios有攔截器功能(axios.interceptors)。遇到須要在全部ajax請求以前或者請求完成以後作一些事情的話,咱們就能夠在攔截器中寫。攔截器能夠在發起請求以前攔截請求,對請求作一些處理,而後,再繼續請求;也能夠在請求完成以後攔截請求,對響應結果作一些處理,而後再把結果返回。axios
這樣作的好處是咱們不須要在每一個請求的時候,都去寫相同的這些代碼,能夠把全局生效/通用的處理放在攔截器中來實現。能夠省去不少代碼,也避免了咱們在開發時,不當心某一個請求漏掉了作全局處理。api
你能夠在then和catch以前攔截請求和響應。promise
// 添加一個請求攔截器
c_fetch.interceptors.request.use(function (config) {
// Do something before request is sent
return config;
});
// 添加一個響應攔截器
c_fetch.interceptors.response.use(function (response) {
// Do something with response data
return response;
});
複製代碼
語法:
Promise<Response> fetch(input[, init]);
複製代碼
參數:
?input
定義要獲取的資源。這多是:
一個 USVString 字符串,包含要獲取資源的 URL。一些瀏覽器會接受 blob: 和 data: 做爲 schemes.
一個 Request 對象。
init 可選
一個配置項對象,包括全部對請求的設置。可選的參數有:
method: 請求使用的方法,如 GET、POST。
headers: 請求的頭信息,形式爲 Headers 的對象或包含 ByteString 值的對象字面量。
body: 請求的 body 信息:多是一個 Blob、BufferSource、FormData、URLSearchParams 或者 USVString 對象。注意 GET 或 HEAD 方法的請求不能包含 body 信息。
mode: 請求的模式,如 cors、 no-cors 或者 same-origin。
credentials: 請求的 credentials,如 omit、same-origin 或者 include。爲了在當前域名內自動發送 cookie , 必須提供這個選項, 從 Chrome 50 開始, 這個屬性也能夠接受 FederatedCredential 實例或是一個 PasswordCredential 實例。
cache: 請求的 cache 模式: default 、 no-store 、 reload 、 no-cache 、 force-cache 或者 only-if-cached 。
redirect: 可用的 redirect 模式: follow (自動重定向), error (若是產生重定向將自動終止而且拋出一個錯誤), 或者 manual (手動處理重定向). 在Chrome中,Chrome 47以前的默認值是 follow,從 Chrome 47開始是 manual。
referrer: 一個 USVString 能夠是 no-referrer、client或一個 URL。默認是 client。
referrerPolicy: Specifies the value of the referer HTTP header. May be one of no-referrer、 no-referrer-when-downgrade、 origin、 origin-when-cross-origin、 unsafe-url 。
integrity: 包括請求的 subresource integrity 值 ( 例如: sha256-BpfBw7ivV8q2jLiT13fxDYAe2tJllusRSZ273h2nFSE=)。
複製代碼
原生fetch的詳細文檔請移步MDN查閱:
developer.mozilla.org/zh-CN/docs/…瀏覽器
從上面的fetch的語法解釋和參數解釋,咱們能夠知道fetch是個函數;接收兩個參數,第一個參數定義要獲取的資源,第二個參數爲可選項,一個配置項對象,包括全部對請求的設置;fetch函數分返回結果是一個promise對象。cookie
function c_fetch (input, init = {}) {
//fetch默認請求方式設爲GET
if(!init.method){
init.method = 'GET'
}
//interceptors_req是攔截請求的攔截處理函數集合
//後面會講解interceptors_req的定義與實現
interceptors_req.forEach(interceptors => {
init = interceptors(init);
})
//在原生fetch外面封裝一個promise,爲了在promise裏面能夠對fetch請求的結果作攔截處理。
//同時,保證c_fetch函數返回的結果是個promise對象。
return new Promise(function (resolve, reject) {
//發起fetch請求,fetch請求的形參是接收上層函數的形參
fetch(input, init).then(res => {
//interceptors_res是攔截響應結果的攔截處理函數集合
//後面會講解interceptors_res的定義與實現
interceptors_res.forEach(interceptors => {
//攔截器對響應結果作處理,把處理後的結果返回給響應結果。
res = interceptors(res);
})
//將攔截器處理後的響應結果resolve出去
resolve(res)
}).catch(err => {
reject(err);
})
})
}
複製代碼
//定義用來存儲攔截請求和攔截響應結果的處理函數集合
let interceptors_req = [], interceptors_res = [];
function c_fetch (input, init = {}) {
//fetch默認請求方式設爲GET
if(!init.method){
init.method = 'GET'
}
//interceptors_req是攔截請求的攔截處理函數集合
interceptors_req.forEach(interceptors => {
init = interceptors(init);
})
//在原生fetch外面封裝一個promise,爲了在promise裏面能夠對fetch請求的結果作攔截處理。
//同時,保證c_fetch函數返回的結果是個promise對象。
return new Promise(function (resolve, reject) {
//發起fetch請求,fetch請求的形參是接收上層函數的形參
fetch(input, init).then(res => {
//interceptors_res是攔截響應結果的攔截處理函數集合
interceptors_res.forEach(interceptors => {
//攔截器對響應結果作處理,把處理後的結果返回給響應結果。
res = interceptors(res);
})
//將攔截器處理後的響應結果resolve出去
resolve(res)
}).catch(err => {
reject(err);
})
})
}
//在c_fetch函數上面增長攔截器interceptors,攔截器提供request和response兩種攔截器功能。
//能夠經過request和response的use方法來綁定兩種攔截器的處理函數。
//use方法接收一個參數,參數爲一個callback函數,callback函數用來做爲攔截器的處理函數;
//request.use方法會把callback放在interceptors_req中,等待執行。
//response.use方法會把callback放在interceptors_res中,等待執行。
//攔截器的處理函數callback接收一個參數。
//request攔截器的callback接收的是請求發起前的config;
//response攔截器的callback接收的是網絡請求的response結果。
c_fetch.interceptors = {
request: {
use: function (callback) {
interceptors_req.push(callback);
}
},
response: {
use: function (callback) {
interceptors_res.push(callback);
}
}
}
複製代碼
/** * c_fetch * 基於原生fetch封裝了攔截器功能,暴露出來的c_fetch跟原生fetch用法一致,只是增長了攔截器功能。攔截器用法參考axios的攔截器用法。 * 攔截器: c_fetch.interceptors * 注意: 攔截器不攔截reject類型的response結果 */
//定義用來存儲攔截請求和攔截響應結果的處理函數集合
let interceptors_req = [], interceptors_res = [];
function c_fetch (input, init = {}) {
//fetch默認請求方式設爲GET
if(!init.method){
init.method = 'GET'
}
//interceptors_req是攔截請求的攔截處理函數集合
interceptors_req.forEach(interceptors => {
init = interceptors(init);
})
//在原生fetch外面封裝一個promise,爲了在promise裏面能夠對fetch請求的結果作攔截處理。
//同時,保證c_fetch函數返回的結果是個promise對象。
return new Promise(function (resolve, reject) {
//發起fetch請求,fetch請求的形參是接收上層函數的形參
fetch(input, init).then(res => {
//interceptors_res是攔截響應結果的攔截處理函數集合
interceptors_res.forEach(interceptors => {
//攔截器對響應結果作處理,把處理後的結果返回給響應結果。
res = interceptors(res);
})
//將攔截器處理後的響應結果resolve出去
resolve(res)
}).catch(err => {
reject(err);
})
})
}
//在c_fetch函數上面增長攔截器interceptors,攔截器提供request和response兩種攔截器功能。
//能夠經過request和response的use方法來綁定兩種攔截器的處理函數。
//use方法接收一個參數,參數爲一個callback函數,callback函數用來做爲攔截器的處理函數;
//request.use方法會把callback放在interceptors_req中,等待執行。
//response.use方法會把callback放在interceptors_res中,等待執行。
//攔截器的處理函數callback接收一個參數。
//request攔截器的callback接收的是請求發起前的config;
//response攔截器的callback接收的是網絡請求的response結果。
c_fetch.interceptors = {
request: {
use: function (callback) {
interceptors_req.push(callback);
}
},
response: {
use: function (callback) {
interceptors_res.push(callback);
}
}
}
export default c_fetch;
複製代碼
本篇文章只是實現了一個最基本的攔截器功能,文章字數有限,沒有深刻講解更加成熟的攔截器實現方式。有興趣的朋友能夠閱讀下axios的攔截器實現,頗有意思的。axios的攔截器會更加完善。網絡
我這裏針對fetch的封裝也只是最基本的封裝,目的是講解攔截器的實現,沒有過於複雜化。上文中暴露出來的c_fetch其實能夠在封裝一層cc_fetch,用bind方法把c_fetch的方法綁定在cc_fetch上,最後暴露出來的是cc_fetch。這樣作的好處是保護了c_fetch的方法不會被外部所影響,篡改等。固然了,這只是我我的的一些見解,不表明全部人。cors
最後謝謝各位可以堅持閱讀到最後,但願您閱讀本篇文章可以有所收穫。謝謝🙏~