内容简介:为什么要给fetch增加拦截器?浏览器提供的fetch方法不够用吗?是的。原生fetch确实不够用。在项目中,如果想要在所有的网络请求之前往header中加入权限信息(比如:authorization=xxxx)。用原生fetch的话,你只能在每个fetch请求的时候,header配置中写上authorization=xxxx。或者在请求结果返回来之后,对响应结果做一些特殊处理,在原生fetch中,我们只能在每个请求的结果回来之后,都写一遍特殊处理。这样做起来一点都不优雅,一点都不高级。相信每一个程序员都是
为什么要给fetch增加拦截器?浏览器提供的fetch方法不够用吗?
是的。原生fetch确实不够用。
在项目中,如果想要在所有的网络请求之前往header中加入权限信息(比如:authorization=xxxx)。用原生fetch的话,你只能在每个fetch请求的时候,header配置中写上authorization=xxxx。或者在请求结果返回来之后,对响应结果做一些特殊处理,在原生fetch中,我们只能在每个请求的结果回来之后,都写一遍特殊处理。这样做起来一点都不优雅,一点都不高级。相信每一个 程序员 都是一个懒人,能用少量代码实现出更优雅,更健壮程序的话,绝对不用大量代码实现一个很脆弱的程序。
用过axios的人,都知道axios有拦截器功能(axios.interceptors)。遇到需要在所有ajax请求之前或者请求完成之后做一些事情的话,我们就可以在拦截器中写。拦截器可以在发起请求之前拦截请求,对请求做一些处理,然后,再继续请求;也可以在请求完成之后拦截请求,对响应结果做一些处理,然后再把结果返回。
这样做的好处是我们不需要在每个请求的时候,都去写相同的这些代码,可以把全局生效/通用的处理放在拦截器中来实现。可以省去很多代码,也避免了我们在开发时,不小心某一个请求漏掉了做全局处理。
拦截器设计思考
- 目的是在原生fetch基础之上增加拦截请求的功能。
- 封装后,最终暴露在外面的接口应该于原生fetch的使用方法一致,同时增加拦截器功能
- 拦截器的API设计参考axios的拦截器(个人比较喜欢axios的拦截器设计)。
拦截器API使用方法
你可以在then和catch之前拦截请求和响应。
// 添加一个请求拦截器
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;
});
复制代码
拦截器实现方案
-
为了保证封装后的fetch暴露在最外面的api跟原生fetch保持一致。所以,我们要暴露到最外面的api应该是个跟fetch接收相同参数的函数。
我们看下原生fetch方法语法解释和接收参数解释。
语法: 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对象。
- 我们先来实现封装后,暴露出来的c_fetch函数。
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);
})
})
}
复制代码
- c_fetch 函数实现完了,我们就差拦截器的实现了。我们在 c_fetch 函数的基础上增加interceptors,用来注册拦截器。
//定义用来存储拦截请求和拦截响应结果的处理函数集合
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);
}
}
}
复制代码
- 最后将整个封装之后,含有拦截器功能的fetch包装为一个插件暴露给开发者使用。
/**
* c_fetch
* 基于原生fetch封装了拦截器功能,暴露出来的c_fetch跟原生fetch用法一致,只是增加了拦截器功能。拦截器用法参考axios的拦截器用法。
* 拦截器: c_fetch.interceptors
* 注意: 拦截器不拦截reject类型的response结果
*/
(function () {
//定义用来存储拦截请求和拦截响应结果的处理函数集合
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的方法不会被外部所影响,篡改等。当然了,这只是我个人的一些看法,不代表所有人。
最后谢谢各位能够坚持阅读到最后,希望您阅读本篇文章能够有所收获。谢谢:pray:~
以上所述就是小编给大家介绍的《基于原生fetch封装一个带有拦截器功能的fetch,类似axios的拦截器》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- 前端架构之vue+axios 前端实现登录拦截(路由拦截、http拦截)
- react离开页面,自定义弹框拦截,路由拦截
- Springboot整合Hibernate拦截器时无法向拦截器注入Bean
- SpringMVC拦截器
- IOS 拦截器
- angular 拦截器
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Head First HTML and CSS
Elisabeth Robson、Eric Freeman / O'Reilly Media / 2012-9-8 / USD 39.99
Tired of reading HTML books that only make sense after you're an expert? Then it's about time you picked up Head First HTML and really learned HTML. You want to learn HTML so you can finally create th......一起来看看 《Head First HTML and CSS》 这本书的介绍吧!
JS 压缩/解压工具
在线压缩/解压 JS 代码
HEX HSV 转换工具
HEX HSV 互换工具