标题: Web前端开发基础不牢,源码拾遗系列之Axios(1),Jetpack-MVVM高频提问息争 [打印本页] 作者: 耶耶耶耶耶 时间: 2024-9-26 14:39 标题: Web前端开发基础不牢,源码拾遗系列之Axios(1),Jetpack-MVVM高频提问息争 所以防范伪造请求的关键就是检查请求泉源,refferer 字段虽然可以标识当前站点,但是不敷可靠,如今业界比力通用的解决方案照旧在每个请求上附带一个 anti-CSRF token,这个的原理是攻击者无法拿到 Cookie,所以我们可以通过对 Cookie 进行加密(比如对 sid 进行加密),然后配合服务端做一些简单的验证,就可以判定当前请求是不是伪造的。
Axios 简单地实现了对特殊 csrf token 的支持,
// Add xsrf header
// This is only done if running in a standard browser environment.
// Specifically not if we’re in a web worker, or react-native.
if (utils.isStandardBrowserEnv()) {
// Add xsrf header
var xsrfValue = (config.withCredentials || isURLSameOrigin(fullPath)) && config.xsrfCookieName ?
cookies.read(config.xsrfCookieName) :
undefined;
if (xsrfValue) {
requestHeaders[config.xsrfHeaderName] = xsrfValue;
}
}
Interceptor
拦截器是 Axios 的一个特色 Feature,我们先简单回首下使用方式,
// 拦截器可以拦截请求或响应
// 拦截器的回调将在请求或响应的 then 或 catch 回调前被调用
var instance = axios.create(options);
var requestInterceptor = axios.interceptors.request.use(
(config) => {
// do something before request is sent
return config;
},
(err) => {
// do somthing with request error
return Promise.reject(err);
}
);
// 移除已设置的拦截器
axios.interceptors.request.eject(requestInterceptor)
那么拦截器是怎么实现的呢?
定位到源码 lib/core/Axios.js 第 14 行,
function Axios(instanceConfig) {
this.defaults = instanceConfig;
this.interceptors = {
request: new InterceptorManager(),
response: new InterceptorManager()
};
}
通过 Axios 的构造函数可以看到,拦截器 interceptors 中的 request 和 response 两者都是一个叫做 InterceptorManager 的实例,这个 InterceptorManager 是什么?
定位到源码 lib/core/InterceptorManager.js,
function InterceptorManager() {
this.handlers = [];
}
InterceptorManager.prototype.use = function use(fulfilled, rejected, options) {
this.handlers.push({
fulfilled: fulfilled,
rejected: rejected,
synchronous: options ? options.synchronous : false,
runWhen: options ? options.runWhen : null
});
return this.handlers.length - 1;
};
InterceptorManager.prototype.eject = function eject(id) {
if (this.handlers[id]) {
this.handlers[id] = null;
}
};
InterceptorManager.prototype.forEach = function forEach(fn) {
utils.forEach(this.handlers, function forEachHandler(h) {
if (h !== null) {
fn(h);
}
});
}; InterceptorManager 是一个简单的变乱管理器,实现了对拦截器的管理,
通过 handlers 存储拦截器,然后提供了添加,移除,遍历执行拦截器的实例方法,存储的每一个拦截器对象都包含了作为 Promise 中 resolve 和 reject 的回调以及两个配置项。
值得一提的是,移除方法是通过直接将拦截器对象设置为 null 实现的,而不是 splice 剪切数组,遍历方法中也增加了相应的 null 值处置惩罚。如许做一方面使得每一项ID保持为项的数组索引不变,另一方面也避免了重新剪切拼接数组的性能损失。
拦截器的回调会在请求或响应的 then 或 catch 回调前被调用,这是怎么实现的呢?
回到源码 lib/core/Axios.js 中第 27 行,Axios 实例对象的 request 方法,
我们提取其中的关键逻辑如下,
Axios.prototype.request = function request(config) {
// Get merged config
// Set config.method
// …
var requestInterceptorChain = [];
this.interceptors.request.forEach(function unshiftRequestInterceptors(interceptor) {
requestInterceptorChain.unshift(interceptor.fulfilled, interceptor.rejected);
});
var responseInterceptorChain = [];
this.interceptors.response.forEach(function pushResponseInterceptors(interceptor) {
responseInterceptorChain.push(interceptor.fulfilled, interceptor.rejected);
});
var promise;
var chain = [dispatchRequest, undefined];
Array.prototype.unshift.apply(chain, requestInterceptorChain);
chain.concat(responseInterceptorChain);
promise = Promise.resolve(config);
while (chain.length) {
promise = promise.then(chain.shift(), chain.shift());
}
return promise;
};
可以看到,当执行 request 时,实际的请求(dispatchRequest)和拦截器是通过一个叫 chain 的队列来管理的。整个请求的逻辑如下,