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 的队列来管理的。整个请求的逻辑如下,

  1. 首先初始化请求和响应的拦截器队列,将 resolve,reject 回调依次放入队头

  2. 然后初始化一个 Promise 用来执行回调,chain 用来存储和管理实际请求和拦截器

  3. 将请求拦截器放入 chain 队头,响应拦截器放入 chain 队尾

  4. 队列不为空时,通过 Promise.then 的链式调用,依次将请求拦截器,实际请求,响应拦截器出队

  5. 最后返回链式调用后的 Promise

这里的实际请求是对适配器的封装,请求和响应数据的转换都在这里完成。

那么数据转换是如何实现的呢?

Transform data

定位到源码 lib/core/dispatchRequest.js

function dispatchRequest(config) {

throwIfCancellationRequested(config);

// Transform request data

config.data = transformData(

config.data,

config.headers,

config.transformRequest

);

var adapter = config.adapter || defaults.adapter;

return adapter(config).then(function onAdapterResolution(response) {

throwIfCancellationRequested(config);

// Transform response data

response.data = transformData(

response.data,

response.headers,

config.transformResponse

);

return response;

}, function onAdapterRejection(reason) {

if (!isCancel(reason)) {

throwIfCancellationRequested(config);

// Transform response data

if (reason && reason.response) {

reason.response.data = transformData(

reason.response.data,

reason.response.headers,

config.transformResponse

);

}

}

return Promise.reject(reason);

});

};

这里的 throwIfCancellationRequested 方法用于取消请求,关于取消请求稍后我们再讨论,可以看到发送请求是通过调用适配器实现的,在调用前和调用后会对请求和响应数据进行转换。

转换通过 transformData 函数实现,它会遍历调用设置的转换函数,转换函数将 headers 作为第二个参数,所以我们可以根据 headers 中的信息来执行一些不同的转换操作,

// 源码 core/transformData.js

function transformData(data, headers, fns) {

utils.forEach(fns, function transform(fn) {

data = fn(data, headers);

});

return data;

};

Axios 也提供了两个默认的转换函数,用于对请求和响应数据进行转换。默认情况下,

Axios 会对请求传入的 data 做一些处理,比如请求数据如果是对象,会序列化为 JSON 字符串,响应数据如果是 JSON 字符串,会尝试转换为 JavaScript 对象,这些都是非常实用的功能,

对应的转换器源码可以在 lib/default.js 的第 31 行找到,

var defaults = {

// Line 31

transformRequest: [function transformRequest(data, headers) {

normalizeHeaderName(headers, ‘Accept’);

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数前端工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加V获取:vip1024c (备注前端)
img

文末

技术是没有终点的,也是学不完的,最重要的是活着、不秃。

零基础入门的时候看书还是看视频,我觉得成年人,何必做选择题呢,两个都要。喜欢看书就看书,喜欢看视频就看视频。

最重要的是在自学的过程中,一定不要眼高手低,要实战,把学到的技术投入到项目当中,解决问题,之后进一步锤炼自己的技术。

自学最怕的就是缺乏自驱力,一定要自律,杜绝“三天打鱼两天晒网”,到最后白忙活一场。

高度自律的同时,要保持耐心,不抛弃不放弃,切勿自怨自艾,每天给自己一点点鼓励,学习的劲头就会很足,不容易犯困。

技术学到手后,找工作的时候一定要好好准备一份简历,不要无头苍蝇一样去海投简历,容易“竹篮打水一场空”。好好的准备一下简历,毕竟是找工作的敲门砖。

拿到面试邀请后,在面试的过程中一定要大大方方,尽力把自己学到的知识舒适地表达出来,不要因为是自学就不够自信,给面试官一个好的印象,面试成功的几率就会大很多,加油吧,骚年!

CodeChina开源项目:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】

一个人可以走的很快,但一群人才能走的更远。如果你从事以下工作或对以下感兴趣,欢迎戳这里加入程序员的圈子,让我们一起学习成长!

AI人工智能、Android移动开发、AIGC大模型、C C#、Go语言、Java、Linux运维、云计算、MySQL、PMP、网络安全、Python爬虫、UE5、UI设计、Unity3D、Web前端开发、产品经理、车载开发、大数据、鸿蒙、计算机网络、嵌入式物联网、软件测试、数据结构与算法、音视频开发、Flutter、IOS开发、PHP开发、.NET、安卓逆向、云计算

准备一下简历,毕竟是找工作的敲门砖。

拿到面试邀请后,在面试的过程中一定要大大方方,尽力把自己学到的知识舒适地表达出来,不要因为是自学就不够自信,给面试官一个好的印象,面试成功的几率就会大很多,加油吧,骚年!

CodeChina开源项目:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】

一个人可以走的很快,但一群人才能走的更远。如果你从事以下工作或对以下感兴趣,欢迎戳这里加入程序员的圈子,让我们一起学习成长!

AI人工智能、Android移动开发、AIGC大模型、C C#、Go语言、Java、Linux运维、云计算、MySQL、PMP、网络安全、Python爬虫、UE5、UI设计、Unity3D、Web前端开发、产品经理、车载开发、大数据、鸿蒙、计算机网络、嵌入式物联网、软件测试、数据结构与算法、音视频开发、Flutter、IOS开发、PHP开发、.NET、安卓逆向、云计算

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值