1.一文读懂Axios核心源码思想
2.JS逆向 | *毛租(AES),一个较难分析的网站
3.Vue项目性能优化实操,从50分到80分
4.axios,如何中断请求?
5.Axios源码深度剖析 - AJAX新王者
6.分析axios源码来找出无法使用all和spread等方法的原因
一文读懂Axios核心源码思想
阅读本文后,理解 Axios 的核心源码思想将变得清晰。 全文共计约两千字,阅读耗时大约为六分钟,以 Axios 版本 0..1 为例。源码大叔 文章以特性为入口,解答 Axios 的本质并感受其封装艺术。适配器与兼容性
Axios 能同时用于浏览器和 Node.js 的原因在于其适配器逻辑,通过检测环境变量,决定使用 XMLHTTPREQUEST 或 Node.js HTTP 创建请求。此逻辑位于 lib/defaults.js 文件中。 适配器的判断逻辑如下:根据环境变量,决定使用哪种适配器。在 SSR 服务端渲染时,同样能复用此逻辑。XMLHttpRequest 与封装
定位至 lib/adapters/xhr.js 文件,整体结构导出一个函数,接收配置参数并返回 Promise。关键部分如下:创建 xhr 对象、open 启动请求、监听 xhr 状态并 send 发送请求。 对于 onreadystatechange 的处理:过滤状态,仅在请求完成时(readyState === 4)处理,注意文件协议请求成功状态码可能为 0 的特殊情况,Axios 已处理。 请求完成后,响应被包装为标准格式的对象,并作为参数传递给 settle 方法,该方法在 lib/core/settle.js 文件中定义,用于 Promise 回调的封装。XSRF 防范与安全
Axios 对 CSRF 攻击的防范通过请求头实现,用户登录后,服务器在响应头中添加 Set-Cookie 存储登录凭证,浏览器存储 Cookie 以保持登录态。 防范方法:攻击者无法获取 Cookie,通过对 Cookie 进行加密配合服务端验证判断请求合法性。Axios 实现了对特殊 CSRF token 的支持。拦截器功能
Axios 的拦截器功能允许用户自定义请求和响应处理逻辑。通过 Axios 构造函数,request 和 response 拦截器被实例化为 InterceptorManager。 InterceptorManager 是equlas源码一个事件管理器,实现拦截器管理,存储拦截器并提供添加、移除、执行拦截器的实例方法。移除和遍历方法优化性能,保持索引不变。数据转换与请求控制
数据转换通过 transformData 函数实现,它遍历设置的转换函数,利用 headers 信息执行转换操作。默认转换处理了数据序列化与 JSON 转换,源码位于 lib/default.js 的第 行。 Axios 支持取消请求,通过 CancelToken 实现。用户可从外部调用 CancelToken 的 resolve 回调,适配器中的 promise then 回调将调用 abort 方法取消请求。总结
Axios 通过适配器实现了在不同环境下的兼容性,大量使用 Promise 和闭包实现状态控制,拦截器、取消请求功能体现了其简洁封装的艺术。JS逆向 | *毛租(AES),一个较难分析的网站
目标网站加密分析
在研究特定网站时,发现其参数与响应信息被加密,而此加密方式未直接暴露参数名,因此传统搜索方法无法应用。此网站的请求采用POST方式,使用XHR断点或查看Initiator堆栈的方法,希望能揭露加密细节。
经过分析,发现可疑部分可能与未加密前的参数相关联,并在axios.post函数中执行了一个promise的异步请求。随后,加密处理发生在then后面的函数内,因此加密过程很可能在此函数中进行。尝试跟进代码执行流程,发现加密位置在axios.post函数内。
通过开发者工具,发现源代码映射问题,通过取消映射设置,成功获取加密前的真实代码。加密算法确定为AES,此部分处理较为直接,1010111源码主要涉及加解密操作。经过分析后,可以直接处理加密问题,解决方法相对简单。
为验证解密结果,已将完整代码上传至GitHub,欢迎查看与运行。同时,分享的代码包含了加密处理的完整流程与解密步骤,方便读者学习与实践。
总结此分析过程,关键在于识别加密位置、取消代码映射以获取原始代码,以及识别加密算法(AES)进行解密操作。相关代码与详细步骤已整理并提供,希望对学习加密处理与逆向工程的读者有所帮助。
Vue项目性能优化实操,从分到分
分析性能
在进行具体的优化之前,我们需要借助工具,分析一下性能。以下操作推荐在浏览器无痕模式下进行,可以多测几次,取一个平均值,避免网络波动带来较大的误差!
chrometoolsnetwork查看请求信息
lighthouse收集网页性能指标
webpack-bundle-analyzer查看打包模块依赖关系和包体大小
vue-cli3是内置了webpack-bundle-analyzer插件,我们可以直接通过"build:report":"vue-cli-servicebuild--report"命令生成report.html文件进行查看。
打包体积优化从上图中可以看出,打包出来比较大的模块主要是moment,xlsx,quill,ant-designicon,针对这些插件都可以做出优化。
移除moment的所有本地文件constwebpack=require('webpack');module.exports={ plugins:[//忽略moment.js的所有本地文件newwebpack.IgnorePlugin(/^\.\/locale$/,/moment$/),],};antdesignvue的icon按需加载antdesignvue提供的icon很多,打包出来有+kb,其实很多我们都用不上,需要对其进行按需加载处理。
//antIcons.js//outLineexport{ defaultasCopyOutline}from'@ant-design/icons/lib/outline/CopyOutline';export{ defaultasCloseCircleOutline}from'@ant-design/icons/lib/outline/CloseCircleOutline';export{ defaultasWarningOutline}from'@ant-design/icons/lib/outline/WarningOutline';//fillexport{ defaultasExclamationCircleFill}from'@ant-design/icons/lib/fill/ExclamationCircleFill';export{ defaultasCloseCircleFill}from'@ant-design/icons/lib/fill/CloseCircleFill';export{ defaultasCheckCircleFill}from'@ant-design/icons/lib/fill/CheckCircleFill';//vue.config.jsmodule.exports={ chainWebpack:(config)=>{ config.resolve.alias.set('@$',resolve('src')).set('@ant-design/icons/lib/dist$',resolve('src/plugins/antdIcons.js'));}}按需加载,会导致一些内部组件使用的icon丢失,也需要手动给它导入一下。
三方库配置CDN链接//vue.config.jsconstassetsCDN={ //webpackbuildexternalsexternals:{ vue:'Vue','vue-router':'VueRouter',vuex:'Vuex',axios:'axios',xlsx:'XLSX',quill:'Quill'},js:['//cdn.xxx.com/vue@2.6.0.min.js','//cdn.xxx.com/vue-router@3.5.3.min.js','//cdn.xxx.com/vuex@3.1.1.min.js','//cdn.xxx.com/axios@0..2.min.js','//cdn.xxx.com/xlsx.core.min.js','//cdn.xxx.com/quill_v1.3.6.min.js']};module.exports={ configureWebpack:{ //打包时遇到这些externals,就不把它们打进去externals:isProd?assetsCDN.externals:{ }},chainWebpack:(config)=>{ if(isProd){ //把cdn的地址添加到index.html页面中config.plugin('html').tap(args=>{ args[0].cdn=assetsCDN;returnargs;});}}}externals是key-value的形式,key是package.json中安装的包名,value是包真实注册或者说暴露的全局变量的值,比如vue-router的value是VueRouter,打开vue-router的源码,格式化可以看到如下,注册的DLMS源码值是VueRouter,其他的插件类似。
xlsx的处理在用xlsx做前端导出excel功能时,网上大部分代码中都是用script-loader去加载xlsx的:
require('script-loader!xlsx/dist/xlsx.core.min');....这样做并不能实现externals的功能,最后打包出来还是会引入一个xlsx.core.min.js文件,其实最新的xlsx已经支持import方式引入了:
importXLSXfrom'xlsx'cdn地址有条件的情况下,最好用公司内部的,预防第三方cdn失效,导致线上崩溃,不能使用。
压缩yarnaddimage-webpack-loader-Dconfig.module.rule('images').use('image-webpack-loader').loader('image-webpack-loader').options({ bypassOnDebug:true}).end();其实我更喜欢在拿到的时候,就用第三方工具压缩一下,还可以比较好的保证的清晰度。使用插件压缩,还会增加打包时间,看取舍吧。
推荐一个在线压缩,最高压缩可达%,比插件的效果好。
打包时间优化speed-measure-webpack-plugin打包时间分析yarnaddspeed-measure-webpack-plugin-D//vue.config.jsconstSpeedMeasurePlugin=require("speed-measure-webpack-plugin");constsmp=newSpeedMeasurePlugin();module.exports={ configureWebpack:smp.wrap({ plugins:[newMyPlugin(),newMyOtherPlugin()],});}运行打包命令的时候就可以看到每个loader和plugin执行耗时:?
speed-measure-webpack-plugin,会大大加大打包的时间,所以部署上线的时候最好是注释掉。
Happypack多进程打包//antIcons.js//outLineexport{ defaultasCopyOutline}from'@ant-design/icons/lib/outline/CopyOutline';export{ defaultasCloseCircleOutline}from'@ant-design/icons/lib/outline/CloseCircleOutline';export{ defaultasWarningOutline}from'@ant-design/icons/lib/outline/WarningOutline';//fillexport{ defaultasExclamationCircleFill}from'@ant-design/icons/lib/fill/ExclamationCircleFill';export{ defaultasCloseCircleFill}from'@ant-design/icons/lib/fill/CloseCircleFill';export{ defaultasCheckCircleFill}from'@ant-design/icons/lib/fill/CheckCircleFill';0//antIcons.js//outLineexport{ defaultasCopyOutline}from'@ant-design/icons/lib/outline/CopyOutline';export{ defaultasCloseCircleOutline}from'@ant-design/icons/lib/outline/CloseCircleOutline';export{ defaultasWarningOutline}from'@ant-design/icons/lib/outline/WarningOutline';//fillexport{ defaultasExclamationCircleFill}from'@ant-design/icons/lib/fill/ExclamationCircleFill';export{ defaultasCloseCircleFill}from'@ant-design/icons/lib/fill/CloseCircleFill';export{ defaultasCheckCircleFill}from'@ant-design/icons/lib/fill/CheckCircleFill';1HardSourceWebpackPlugin打包缓存//antIcons.js//outLineexport{ defaultasCopyOutline}from'@ant-design/icons/lib/outline/CopyOutline';export{ defaultasCloseCircleOutline}from'@ant-design/icons/lib/outline/CloseCircleOutline';export{ defaultasWarningOutline}from'@ant-design/icons/lib/outline/WarningOutline';//fillexport{ defaultasExclamationCircleFill}from'@ant-design/icons/lib/fill/ExclamationCircleFill';export{ defaultasCloseCircleFill}from'@ant-design/icons/lib/fill/CloseCircleFill';export{ defaultasCheckCircleFill}from'@ant-design/icons/lib/fill/CheckCircleFill';2//antIcons.js//outLineexport{ defaultasCopyOutline}from'@ant-design/icons/lib/outline/CopyOutline';export{ defaultasCloseCircleOutline}from'@ant-design/icons/lib/outline/CloseCircleOutline';export{ defaultasWarningOutline}from'@ant-design/icons/lib/outline/WarningOutline';//fillexport{ defaultasExclamationCircleFill}from'@ant-design/icons/lib/fill/ExclamationCircleFill';export{ defaultasCloseCircleFill}from'@ant-design/icons/lib/fill/CloseCircleFill';export{ defaultasCheckCircleFill}from'@ant-design/icons/lib/fill/CheckCircleFill';3第一次打包时间没什么提升,但是第二次开始提升效果就很明显了。在node_modules/.cache中可以看到它的缓存文件。
首屏加载优化分析覆盖率,进行拆包splitChunksChromeDevTools?有一组平行的选项卡,被隐藏在主窗口之下。这个组合被称为?Drawer。当你在?DevTools?(任何选项卡)中时,按?[esc]?来显示它,再次按?[esc]?隐藏它:
通过上图我们可以看出chunk-vendors.js文件的未使用字节数(UnusedBytes)达到了%,这表示首页加载的大部分js都是用不着的。
经过上面的优化,我们可以打包看一下包体分析:chunk-venders很大,它包含了大量的依赖库,ant-design-vue,vxe-table,moment等,我们可以通过splitChunks将这些第三方库进行抽离独立打包。
//antIcons.js//outLineexport{ defaultasCopyOutline}from'@ant-design/icons/lib/outline/CopyOutline';export{ defaultasCloseCircleOutline}from'@ant-design/icons/lib/outline/CloseCircleOutline';export{ defaultasWarningOutline}from'@ant-design/icons/lib/outline/WarningOutline';//fillexport{ defaultasExclamationCircleFill}from'@ant-design/icons/lib/fill/ExclamationCircleFill';export{ defaultasCloseCircleFill}from'@ant-design/icons/lib/fill/CloseCircleFill';export{ defaultasCheckCircleFill}from'@ant-design/icons/lib/fill/CheckCircleFill';4name:打包的chunks的名字
test:匹配到的模块奖杯打进这个缓存组
chunks:代码块类型必须三选一:“initial”(初始化)|“all”(默认就是all)|“async”(动态加载)默认Webpack4只会对按需加载的代码做分割。如果我们需要配置初始加载的代码也加入到代码分割中,可以设置为‘all’
priority:缓存组打包的先后优先级,数值大的优先
minSize:默认是)形成一个新代码块最小的体积
minChunks:(默认是1)在分割之前,这个代码块最小应该被引用的次数
maxInitialRequests:(默认是3)一个入口最大的并行请求数
maxAsyncRequests:(默认是5)按需加载时候最大的并行请求数
reuseExistingChunk:如果当前的chunk已被从split出来,那么将会直接复用这个chunk而不是hyper源码重新创建一个
enforce:告诉webpack忽略splitChunks.minSize,splitChunks.minChunks,splitChunks.maxAsyncRequestsandsplitChunks.maxInitialRequests,总是为这个缓存组创建chunks
开启gzip在nginx下开启gzip有两种方式:
gzipon调用服务器cpu动态打包
gzip_staticon?使用前端已经打包好的gzip文件更快
可以看一下[nginx官方文档配置]。(/post/
axios,如何中断请求?
深入解析 Axios 源码,探讨如何中断请求。在分析过程中,将重点放在了 default.js 文件以及与主动取消 Axios 请求相关的 /cancel 目录,揭示了核心工具方法的运作机制。
在 default.js 中,导出了十个变量和方法,皆服务于默认功能,为理解和使用 Axios 奠定基础。
进一步探索 /cancel 目录,了解与取消请求相关的机制,涉及 cancel token API,需在配置中添加 cancelToken 属性,通过回调函数实现取消功能。
深入分析取消逻辑,从简单的 Cancel 类到 isCancel 方法,再到复杂的 CancelToken 类,逐步揭秘取消请求的内部运作。
关键点在于 CancelToken 类的实现,通过两层闭包巧妙地将“resolve”暴露给外部,同时提供了用于抛出错误和获取工厂方法的原型方法。
总结,本篇解析了默认功能的实现和取消逻辑的核心,为理解 Axios 源码提供了重要视角,下篇将继续深入探讨耦合度较高的工具方法,为开发和优化 Axios 提供更多洞察。
Axios源码深度剖析 - AJAX新王者
Axios 是一个基于 Promise 的 HTTP 请求库,支持浏览器和 Node.js 环境。其源码在 GitHub 上开源,欢迎 fork 使用并提出指正。以下为 Axios 的核心目录结构说明,主要关注在 /lib/ 目录下的文件。
在使用 Axios 时,你可能会遇到多种调用方式,本文将带你深入了解这些方式及其原理。
首先,我们来了解一下 Axios 的基本用法。你可以使用以下几种方式发起请求:
1. `axios(option)`:提供一个配置对象进行调用。
2. `axios(url[, option])`:传入 URL 和配置对象。
3. 对于 GET、DELETE 等方法:`axios[method](url[, option])`。
4. 对于 POST、PUT 等方法:`axios[method](url[, data[, option]])`。
5. 使用默认实例:`axios.request(option)`。
通过以上方式,你可以轻松发起 HTTP 请求。
深入源码分析,你将发现 Axios 的强大之处。通过 `axios.js` 文件的入口,核心在于 `createInstance` 方法,该方法能生成一个指向 `Axios.prototype.request` 的 Function,从而实现多种调用方式。
在 Axios 的核心 `Axios` 类中,`request` 方法是所有功能的中枢,无论是 GET、POST 还是其他方法,最终都通过 `request` 方法实现。
配置项是 Axios 与用户交互的关键,它涵盖了几乎所有功能的配置。配置项从低到高优先级顺序为:默认配置对象、`defaults` 属性、`request` 方法参数。
在使用 Axios 时,配置项是如何生效的?答案在于合并多个配置源,最终得到一个综合配置对象。
此外,Axios 提供了拦截器系统,让你可以控制请求前后的数据处理。每个 Axios 实例都有 `interceptors` 属性,用于管理拦截器,让你实现精细的控制。
核心的 `dispatchRequest` 方法则负责处理请求流程,包括请求适配器、发送请求、数据转换等步骤。最后,通过 Promise,你可以优雅地处理异步请求。
数据转换器让你能轻松地在请求和响应数据之间进行转换,如将对象转换为 JSON 格式。默认情况下,Axios 自动处理 JSON 数据转换。
在使用 Axios 时,你还能灵活地控制超时、取消请求、设置 header、携带 cookie 等功能。通过源码分析,你可以深入理解 Axios 的内部机制。
总结,Axios 以其强大、灵活的功能和简洁的 API 设计,成为现代应用中不可或缺的 HTTP 请求工具。通过本文的深入探讨,你将对 Axios 的运作机制有更深刻的理解,从而更好地利用其功能。
分析axios源码来找出无法使用all和spread等方法的原因
在使用axios进行创建时,若采用axios.create({ })方法,将无法使用all、spread、Cancel、CancelToken、isCancel等方法。
网上关于此问题的解答,通常是axios维护者建议重新引入axios package以解决问题。然而,这种方法并不理想,因为重新引入会导致axios配置丢失,需要重新配置,相当繁琐。
在我们的项目中,经常需要使用自定义设置的axios实例,例如设置基础URL和超时时间。设置完成后,我们可以使用newAxios.post来完成需求。但若尝试使用all、spread、Cancel、CancelToken、isCancel等方法,系统会提示方法不存在。
接下来,我们将分析axios源码,探究为何使用axios.create方法后无法使用all、spread等方法。
首先,打开axios源码目录下的lib/axios.js文件,这是Axios的入口处,也是create函数所在的地方。让我们看一下create的源代码:
接下来,我们将逐步解读代码。mergeConfig方法从字面上可以理解为一个合并配置的方法,即合并我们的配置与默认配置,覆盖默认配置。关于合并配置的代码,这里就不详细介绍了。有兴趣的可以查看mergeConfig。因此,现在的代码如下:
现在,我们来看一下剩下的createInstance函数:
context变量包含axios实例代码。我们只需知道,实例Axios后,context变量原型链上有request、delete、get、head、options、post、put、patch方法,自身有interceptors对象。
现在,让我们看看下面的bind和extend方法:
第一个bind函数是让Axios.prototype.request函数中的this指向context变量。
后面两个extend方法,是把第二个参数的可枚举对象复制到第一个参数中,即instance变量中。
从第一个bind方法开始,现在instance变量中有一个request方法。
然后第二个extend方法,把Axios.prototype里的方法复制到instance变量中。现在instance变量中有request、delete、get、head、options、post、put、patch方法。
最后第三个extend方法,把context里的方法复制到instance变量中。现在变量中有request、delete、get、head、options、post、put、patch、interceptors、defaults。
这样就结束了,create方法直接返回instance变量。我们没有在create方法中看到all、spread等方法。这也是为什么使用create方法后无法使用这些方法。那么这些方法在哪呢?还是在lib/axios.js文件中:
可以看到,这里是把这些方法直接赋值在axios方法上,然后直接暴露出去。所以当我们使用axios时,可以使用all、spread等方法。但使用axios.create就无法使用all、spread、Cancel、CancelToken、isCancel方法。
如果能改axios源码,可以将lib/axios.js修改如下:
但是,这当然不可能。所以,我们需要在不改源代码的情况下实现。
有一个暴力的解决方案,不过我个人比较喜欢:
很简单,一行代码解决问题。这里之所以要加上注释,是因为在eslint中不允许对__proto__进行重新赋值。
TypeScript封装axios——Vue3+Ts实践
在Vue3 + TypeScript的项目中,封装axios库以提升代码质量、降低耦合度并提高维护性。选择封装的原因主要有两个:一是减少每个模块对axios的依赖性,避免因第三方库维护问题而引发的复杂修改;二是解决在发送网络请求时的重复代码问题,如添加token、显示加载等。
通过面向对象的思想封装axios,首先定义了axios实例类型以及响应和请求配置的类型,确保了代码的类型安全。为了解决axios源代码中缺少拦截器属性的问题,引入了接口扩展和类的方法来支持自定义拦截器。在封装的过程中,通过接口定义了拦截器的结构,并且利用类的方法实现了请求和响应的拦截器设置,以及控制加载状态的功能。这样,封装后的axios不仅支持了基本的请求和响应操作,还提供了高度定制化的功能,使得在不同模块中重用相同的网络请求逻辑变得可能。
封装后的axios实例可以作为全局资源在项目中使用,例如在创建request.ts文件中,通过定义HRequest类来管理请求配置和拦截器的设置。这样,每个请求都可以通过HRequest实例调用,同时可以统一管理加载状态,比如在每个请求时显示加载提示。通过将HRequest实例导出,其他部分可以轻松引用,实现代码的复用和维护。
封装后的axios不仅简化了代码结构,提高了代码的可读性和可维护性,还使得项目在扩展和维护过程中变得更加灵活。通过封装,可以方便地在不同项目中重用这一套网络请求处理逻辑,从而节省了开发时间并提高了代码质量。