HTTP拦截器的实现
拦截器分为请求拦截器和响应拦截器,其意思就是请求前做一些事情,响应前做一些事情
axios.interceptors.request.use(function(config){
config.header.fieldName='xxx'
//这里的config就是axios()中的对象
return config;
})
axios.intereptors.response.use(function(data){
data.data='hanldle';
return data;
})
总体的流程如下
requestFulfilled->requestReject->axiosRequest->responseFulfilled->resposeReject
任务注册
axios对象及其构造函数
calss InterceptorManager()
{
//通过观察 use 方法,我们可知注册的拦截器都会被保存到
//InterceptorManager 对象的 handlers 属性中。
this.handlers=[];
use(fulfiller,reject)
{
this.handlers.push({
fulfilled:fulfilled,
rejected:rejected
})
// 返回当前的索引,用于移除已注册的拦截器
return this.handlers.length - 1;
}
}
function Axios(instanceConfig)
{
this.defaults=instanceConfig;
this.interceptors=
{
request:new InterceptorManager(),
response:new InterceptorManager();
}
}
function createInstance(defaultConfig)
{
var context=new Axios(defaultConfig);
var instance=bind(Axios.prototype.request,context);
// Copy axios.prototype to instance
utils.extend(instance, Axios.prototype, context);
// Copy context to instance
utils.extend(instance, context);
return instance;
//该方法最终返回的是 Axios.prototype.request 函数对象
}
var axios = createInstance(defaults);
任务注册完成之后就是执行任务了,但是我们还需要对已经注册的任务进行编排,这样才能保证任务的执行顺序
任务编排
Axios.prototype.request=function request(config)
{
config=mergeConfig(this.defaults,config);
var chain=[dispatchRequest,undefined];
var promise=Promise.resolve(config);
//任务编排
this.interceptors.request.forEach(interceptor=>{
chain.unshift(interceptor.fulfilled, interceptor.rejected);
})
this.interceptors.response.forEach(function pushResponseInterceptors(interceptor) {
chain.push(interceptor.fulfilled, interceptor.rejected);
});
// 任务调度
while (chain.length) {
promise = promise.then(chain.shift(), chain.shift());
}
return promise;
}
HTTP适配器的设计与实现
Axios 同时支持浏览器和 Node.js 环境,对于浏览器环境来说,我们可以通过 XMLHttpRequest 或 fetch API 来发送 HTTP 请求,而对于 Node.js 环境来说,我们可以通过 Node.js 内置的 http 或 https 模块来发送 HTTP 请求。
为了支持不同的环境,Axios 引入了适配器。
function getDefaultAdapter()
{
var adapter;
if(typeof XMLHttpRequest!=='undefined')
{
//for Browsers use XHR adapter
adapter=require('./adapters/xhr')
}
esle if(typeof process!=='undefined')
{
//for Node use HTTP adapter
adapter=require('./adapter/http');
}
return adapter
}
CSRF防御
在下图中攻击者利用了 Web 中用户身份验证的一个漏洞:简单的身份验证只能保证请求发自某个用户的浏览器,却不能保证请求本身是用户自愿发出的
防御手段
- 检查referer字段
以示例中商城操作为例,Referer 字段地址通常应该是商城所在的网页地址,
应该也位于 www.semlinker.com 之下。
而如果是 CSRF 攻击传来的请求,Referer 字段会是包含恶意网址的地址,
不会位于 www.semlinker.com 之下,这时候服务器就能识别出恶意的访问。
但是攻击者可能会篡改referer字段导致不安全
- cookie
- cookie+referer