vue 自 2.0 开始, vue-resource 不再作为官方推荐的 ajax 方案, 转而推荐使用 axios
按照作者的原话来说:
Ajax 本身跟 Vue 并没有什么需要特别整合的地方, 使用 fetch polyfill 或是 axiossuperagent 等等都可以起到同等的效果, vue-resource 提供的价值和其维护成本相比并不划算, 所以决定在不久以后取消对 vue-resource 的官方推荐已有的用户可以继续使用, 但以后不再把 vue-resource 作为官方的 ajax 方案
除了维护成本方面的原因, axios 本身的优点也使得它在一众 ajax 异步请求的框架中脱颖而出, 下面我们通过分析部分 axios 的源码来看看, 是什么让 axios 成为大多数人的选择
GitHub 上 axios 的主页标注了它具有如下特性:
- Make XMLHttpRequests from the browser
- Make http requests from node.js
- Supports the Promise API
- Intercept request and response
- Transform request and response data
- Cancel requests
- Automatic transforms for JSON data
- Client side support for protecting against XSRF
我们来一一分析
同时支持浏览器端和服务端的请求
由于 axios 的这一特性, vue 的 服务端渲染 对于 axios 简直毫无抵抗力 让我们一起来读读源码, 看看它是如何实现的
在 axios/lib/core/dispatchRequest.js 文件中暴露的 dispatchRequest 方法就是 axios 发送请求的方法, 其中有一段代码为:
这段代码首先定义了一个适配器, 然后返回了适配器处理后的内容 如果没有在传入的配置参数中指定适配器, 则取默认配置文件中定义的适配器, 再让我们来看看默认文件 / lib/defaults.js 定义的适配器:
到这里真相大白, XMLHttpRequest 是一个 API, 它为客户端提供了在客户端和服务器之间传输数据的功能; process 对象是一个 global (全局变量), 提供有关信息, 控制当前 Node.js 进程原来作者是通过判断 XMLHttpRequest 和 process 这两个全局变量来判断程序的运行环境的, 从而 在不同的环境提供不同的 http 请求模块, 实现客户端和服务端程序的兼容
同理, 我们在做 ssr 服务端渲染时, 也可以使用这个方法来判断代码当前的执行环境
支持 promise
这一段是 axios 请求整体流程的核心方法, 可以看到请求返回的是一个 promise 对象这样可以让我们的异步请求天然的支持 promise, 方便我们对于异步的处理
支持请求和和数据返回的拦截
依然是上面的核心流程代码, 在设置好请求参数后, 作者定义了一个 chain 数组 , 同时放入了 dispatchRequest, undefined 这两个元素对应 promise 的 resolve 和 reject 方法, 之后将请求拦截器的成功和失败处理依次压入 chain 数组头部 , 将返回拦截器的成功和失败处理依次推入 chain 数组尾部 最后循环取出 chain 数组, 先依次取出 chain 数组中成对的请求拦截处理方法, promise 执行, 然后取出最初定义的 dispatchRequest, undefined 这两个元素执行请求, 最后依次取出 chain 数组中成对的返回拦截器
它的流程可以归纳为
转换请求返回数据, 自动转换 JSON 数据
在 axios/lib/core/dispatchRequest.js 文件中暴露的核心方法 dispatchRequest 中, 有这样两段:
axios 通过设置 transformResponse, 可自动转换请求返回的 json 数据
取消请求
文档上给了两种示例:
第一种:
第二种:
这两种方法都可以取消发出的请求先看具体的流程:
下面来看源码是如何实现的
在 xhr.js 或 http.js 中都有这样一段, 下面取自 /lib/adapters/xhr.js
在请求时如果设置了 cancelToken 参数 , 就会监听来自 cancelToken 的 promise, 一旦来自 cancelToken 的 promise 被触发, 就会执行取消请求的流程
cancelToken 的具体实现为:
就是在上面的代码里, CancelToken 会给自己添加一个 promise 属性, 一旦 cancel 方法 被触发就会执行取消请求的流程
利用这个方法, 一方面可以在按钮的重复点击方面大显身手, 另一方面可以在数据的获取方面直接获取最新的数据
客户端防止 xsrf 攻击
先来了解一下 XSRF, 以下内容来自维基百科
XSRF 跨站请求伪造 (Cross-site request forgery), 是一种挟制用户在当前已登录的 web 应用程序上执行非本意的操作的攻击方法
举个例子:
假如一家网站执行转账的操作 URL 地址如下:
那么, 一个恶意攻击者可以在另一个网站上放置如下代码:
如果有账户名为 Alice 的用户访问了恶意站点, 而她之前刚访问过银行不久, 登录信息尚未过期, 那么她就会损失 1000 资金
------- 我是分割线, 以上内容来自维基百科 -------
axios 是如何做的?
首先, axios 会检查是否是标准的浏览器环境, 然后在标准的浏览器环境中判断, 如果设置了跨域请求时需要凭证且请求的域名和页面的域名相同时, 读取 cookie 中 xsrf token 的值, 并设置到承载 xsrf token 的值的 HTTP 头中
在 node 端支持设置代理
如果在标准浏览器环境则执行 / lib/adapters/xhr.js,axios 不支持 proxy; 如果在 node 环境运行, 用 / lib/adapters/http.js, 支持 proxy
在组内的一个项目中, 使用了 vue 的 ssr 服务端渲染的技术, 其中 ajax 方案就是采用了 axios 由于 ssr 是在服务端请求, 因此在开发测试上线的过程中需要相应的 host 环境例如在开发过程中, 要么需要在程序的请求地址中写上 ip 地址替代域名, 要么需要设置电脑的 host 文件, 改变域名映射的 ip 地址而在测试环境中, 同样需要更改代码或者测试环境的 host 文件这样一来, 如果是改代码的方案则影响了代码的稳定性, 每一次部署都需要修改代码; 如果是修改 host 文件, 则会影响环境的一致性, 假如环境还部署了其他的服务, 还会影响其他服务的测试因此我们组内的男神便使用了 axios 的 proxy 功能, 轻松的解决了这一问题
而在 axios 的源码 / lib/adapters/http.js 中, 则是如此实现代理的:
内部一些针对具体项目环境的二次封装
上面基于源码具体分析了 axios 的各项特性, 下面再来讲一讲我们在具体使用时的一些二次封装由于 axios 使用 get 方式设置参数时, 都需要使用 params 的方式, 例如:
而之前使用 vue-resource 则习惯直接写上参数, 形如:
因此, 对于组内的 axios 统一加了一层封装, 承接之前的使用习惯:
这里需要注意的是, 要确保在提交到服务端的 query 参数中不包含 params 字段, 不然还是要使用默认的参数格式
而对于 post 方式, 则做了如下封装:
axios 使用方便, 功能齐备强大, 其中的一些编程思想也很不入俗套, 是一款前后端通用的 ajax 请求框架, 目前在 github 上已经有接近 36K 的赞, 其优秀程度可见一斑本文通过他的一些特性, 分析了部分源码, 旨在能够在使用它的同时, 更加懂得它
来源: http://www.tuicool.com/articles/U7BFFjj