介绍

image.pngimage.png

https://github.com/axios/axios

中文说明

安装

1、脚手架里面安装
image.png
2、通过npm安装

  1. npm i axios -S

3、通过cdn引入

  1. <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
  2. <!-- 或 -->
  3. <script src="https://unpkg.com/axios/dist/axios.min.js"></script>

引入

在main.js中,添加如下代码

  1. //1.引入axios
  2. import axios from 'axios'
  3. //2.设置默认请求的url
  4. axios.defaults.baseURL = 'http://mockjs.com/api'
  5. //3.设置Vue的默认http请求用axios
  6. Vue.prototype.$http = axios

使用

请求方式

image.png
后面模块主要是使用axios(config)的方式

常见属性

image.png

单个请求

  1. import Vue from 'vue'
  2. import App from './App.vue'
  3. import router from './router'
  4. import store from './store'
  5. import axios from 'axios';
  6. //阻止启动生产消息,如see more tips at xxx.com这些提示
  7. Vue.config.productionTip = false
  8. new Vue({
  9. router,
  10. store,
  11. render: h => h(App)
  12. }).$mount('#app')
  13. //发送一个请求,默认是get,本地也算跨域
  14. axios({
  15. url:'http://localhost:81/ax.php'
  16. }).then(res => { //then支持一个回调函数
  17. console.log(res);
  18. })

并发请求 axios.all([])

  1. axios.all([
  2. axios({}),
  3. axios({})
  4. ]
  5. ).then(res => {
  6. //返回一个数组,里面分别是多个请求的结果
  7. console.log(res[0])
  8. console.log(res[1])
  9. }
  10. )
  1. axios.all([
  2. axios({}),
  3. axios({})
  4. ]
  5. ).then(axios.spread(
  6. //axios.spread(回调函数),可以直接展开
  7. (res0,res1) => {
  8. console.log(res0)
  9. console.log(res1)
  10. }
  11. )

模拟请求

网站:http://httpbin.org/,可以模拟后端,你可以发送各种各样的请求获取数据

====================

封装

好处

为了避免对某个框架(如这里的axios)过度依赖,我们需要对这个框架封装到1个文件中,项目只要都引用这个文件即可。

这样假如axios不再维护要换框架,此时只要改那个文件即可。

JS封装

建议创建network文件夹,里面创建一个专门发送请求的文件
image.png

  1. //1.引入框架(这里是axios)
  2. import axios from 'axios'
  3. // 实际上就是创建了axios的对象实例,也就是一个对象,对象里面有一些方法和属性
  4. //2.导出一个请求函数request到全局,给其他需要的组件引用
  5. /**
  6. * @param {Object} config 全局配置
  7. * @param {Object} success 请求成功时返回
  8. * @param {Object} failure 请求失败时返回
  9. */
  10. export function request(config, success, failure) {
  11. //3.创建这个请求的实例x = axios.create({请求的配置})
  12. const x = axios.create({
  13. //设置路径,可以在其他组件内具体使用时,使用具体的url,而不是在这里统一设置
  14. url:"/",
  15. //设置基本的路径,自动加在 `url` 前面,除非 `url` 是一个绝对 URL
  16. baseURL: "http://localhost:80/php/php",
  17. //设置请求的方法,默认是get
  18. method:"get" ,
  19. // `params` 即将与请求一起发送的get请求的 URL 参数,如/php?ID=12345
  20. // 必须是一个无格式对象(plain object)或 URLSearchParams 对象
  21. // params: {
  22. // ID: 12345
  23. // },
  24. //设置请求方法post
  25. // method:"post" ,
  26. // `data` 是作为post的请求主体被发送的数据
  27. // 只适用于这些请求方法 'PUT', 'POST', 和 'PATCH'
  28. // 在没有设置 `transformRequest` 时,必须是以下类型之一:
  29. // - string, plain object, ArrayBuffer, ArrayBufferView, URLSearchParams
  30. // - 浏览器专属:FormData, File, Blob
  31. // - Node 专属: Stream
  32. // data: {
  33. // firstName: 'Fred'
  34. // },
  35. // `timeout` 指定请求超时的毫秒数(0 表示无超时时间)
  36. // 如果请求话费了超过 `timeout` 的时间,请求将被中断
  37. timeOut: 5000,
  38. // `headers` 是即将被发送的自定义请求头
  39. // headers: {'X-Requested-With': 'XMLHttpRequest'},
  40. // `transformRequest` 允许在向服务器发送前,修改请求数据
  41. // 只能用在 'PUT', 'POST' 和 'PATCH' 这几个请求方法
  42. // 后面数组中的函数必须返回一个字符串,或 ArrayBuffer,或 Stream
  43. // transformRequest: [function (data, headers) {
  44. // // 对 data 进行任意转换处理
  45. // return data;
  46. // }],
  47. // `transformResponse` 拿到服务器数据后,在传递给 then/catch 前,允许修改响应数据
  48. // transformResponse: [function (data) {
  49. // // 对 data 进行任意转换处理
  50. // return data;
  51. // }],
  52. })
  53. //4.当外部调用request函数时,用实例x的配置,发送真正的网络请求
  54. //axios是继承promise的,因此可以直接调用success,failure 作为
  55. //promise的resole 和 reject
  56. return x(config, success, failure)
  57. }

需要用到这个请求时,在模板.vue内,引入并使用

  1. <template>
  2. <el-button type="success" @click="getPerson">成功按钮</el-button>
  3. </template>
  4. <script>
  5. //1.引入这个请求的这个函数
  6. import { request } from '../network/request.js';
  7. export default {
  8. data() {
  9. return {};
  10. },
  11. methods: {
  12. getPerson() {
  13. //2.创建函数,调用request请求
  14. request({
  15. url: 'getUser.php',
  16. })
  17. //成功时返回结果res
  18. .then(res => {
  19. console.log(res.data);
  20. })
  21. //失败时返回结果err
  22. .catch(err =>{
  23. console.log(err);
  24. })
  25. }
  26. }
  27. };
  28. </script>

TS封装

思路就是,把 axios 的实例 axios.create(config),封装成一个自定义请求类 YJLRequest,通过x = new YJLRequest( config ) 的方式创建请求实例,最后通过调用这个 x 的方法发送请求。

为什么要封装成一个类?这样配置可以更灵活,比如
请求1是使用配置1、配置2,就把 请求1 = new YJLRequest( { 配置1 , 配置2} ),直接调用请求1.request() 发送。
请求2是使用配置2、配置3,就把 请求2 = new YJLRequest( { 配置2 , 配置3} ),直接调用请求2.request() 发送。

如果你只是把axios封装成一个函数,这样请求1和请求2共用的是同一个实例,如果配置不一样会比较麻烦(比如配置1是超时时间10秒,配置3是超时时间20秒),每次发送都要手动先修改配置。
image.png

1、封装基础的请求类

image.png
下面是以 Ant Design Vue 2.x 为例子,
把弹窗提示message 和 提示框notification 封装进来,以及把全局Loading封装进来,这样好处是每一个请求开始时都会全屏显示加载中,请求结束后自动取消加载中,若返回的是成功的结果,自动显示操作成功;若返回失败的结果,自动弹出提示框显示失败的内容。

这样不用在外面页面单独配置这些。

而且自定义了3重拦截器,
1、在请求1里面可以自定义拦截器
2、给所有的axios配置了通用的拦截器(弹窗提示message、提示框notification、 全局Loading)
3、外部页面使用时可以自定义拦截器

  1. // =================== 0、引入 ===================
  2. import axios from "axios"
  3. // AxiosInstance 为axios的实例类型
  4. import type { AxiosInstance} from "axios"
  5. // 引入 其他ui组件的加载中弹窗和弹窗的类型
  6. import { message, notification } from "ant-design-vue"
  7. import store from "@/store"
  8. // =================== 1、定义 自定义请求类的 接口 ===================
  9. import type { myRequestConfig,myRequestInterceptors } from "./type";
  10. // =================== 2、封装请求类 ===================
  11. /**
  12. * 自定义请求类;
  13. * 用类进行封装,封装性会更强,而且可以有多个不同的实例
  14. */
  15. class YJLRequest {
  16. // =================== 2.1、类的基本属性 ===================
  17. /** 储存axios的实例 */
  18. instance: AxiosInstance
  19. /** 自定义拦截器 */
  20. interceptors?: myRequestInterceptors
  21. // =================== 2.2、构造函数 ===================
  22. /** 自定义请求 的构造器 */
  23. constructor(config: myRequestConfig) {
  24. // 创建 axios 实例
  25. this.instance = axios.create(config)
  26. // 自定义拦截器,从外面的config传入
  27. this.interceptors = config.interceptors
  28. // =================== 2.2.1、拦截器 ===================
  29. // 1、从 config 中取出自定义拦截器
  30. // 拦截请求
  31. this.instance.interceptors.request.use(
  32. this.interceptors?.requestInterceptor,
  33. this.interceptors?.requestInterceptorCatch
  34. )
  35. // 拦截响应
  36. this.instance.interceptors.response.use(
  37. this.interceptors?.responseInterceptor,
  38. this.interceptors?.responseInterceptorCatch
  39. )
  40. // 2.添加所有的实例都有的拦截器
  41. // 拦截请求
  42. this.instance.interceptors.request.use(
  43. // 发送请求拦截
  44. (config) => {
  45. console.log("所有的实例都有的拦截器: 请求成功拦截")
  46. // 全局加载中
  47. store.commit("showLoading")
  48. return config
  49. },
  50. (err) => {
  51. console.log("所有的实例都有的拦截器: 请求失败拦截")
  52. // 失败提示
  53. notification["error"]({
  54. message: "发送请求失败",
  55. description: `失败原因为:${err}`
  56. })
  57. return err
  58. }
  59. )
  60. // 拦截响应
  61. this.instance.interceptors.response.use(
  62. // 拦截响应
  63. (res) => {
  64. console.log("所有的实例都有的拦截器: 响应成功拦截")
  65. // 取消全局加载中
  66. store.commit("hiddenLoading")
  67. // 响应成功,获取data
  68. const data = res.data
  69. // 这里可以根据不同的返回情况,设置不同的提示
  70. if (res.status === 200) {
  71. // 成功提示
  72. if (!(config.hiddenSuccessMessage === true)) {
  73. message.success({
  74. content: "操作成功",
  75. duration: 1
  76. })
  77. }
  78. return data
  79. } else {
  80. // 失败提示
  81. notification["error"]({
  82. message: "响应失败",
  83. description: `错误代码为:${res.status}`
  84. })
  85. return data
  86. }
  87. },
  88. (err) => {
  89. console.log("所有的实例都有的拦截器: 响应失败拦截")
  90. // 取消全局加载中
  91. store.commit("hiddenLoading")
  92. // 这里可以判断不同的HttpErrorCode显示不同的错误信息
  93. // 失败提示
  94. notification["error"]({
  95. message: "响应失败",
  96. description: `失败原因:${err}`
  97. })
  98. return err
  99. }
  100. )
  101. }
  102. // =================== 2.3、请求方法 ===================
  103. /** 发送请求方法 */
  104. request<T>(config: myRequestConfig<T>): Promise<T> {
  105. // 如果有请求的拦截器,这里可以在传入的时候给你修改一下配置
  106. if (config.interceptors?.requestInterceptor) {
  107. config = config.interceptors.requestInterceptor(config)
  108. }
  109. // 返回 Promise ,让外面可以通过 .then 接收res 或 err
  110. return new Promise((resolve, reject) => {
  111. // 1.单个请求对请求config的处理
  112. if (config.interceptors?.requestInterceptor) {
  113. config = config.interceptors.requestInterceptor(config)
  114. }
  115. // 通过 axios 实例的 request 方法发送请求
  116. this.instance
  117. .request<any,T>(config)
  118. .then((res) => {
  119. // 1.单个请求对数据的处理
  120. if (config.interceptors?.responseInterceptor) {
  121. res = config.interceptors.responseInterceptor(res)
  122. }
  123. // 2.将结果resolve返回出去
  124. resolve(res)
  125. })
  126. .catch((err) => {
  127. reject(err)
  128. })
  129. })
  130. }
  131. // 发送get请求
  132. get<T>(config: myRequestConfig<T>): Promise<T> {
  133. return this.request<T>({ ...config, method: 'GET' })
  134. }
  135. // 发送post请求
  136. post<T>(config: myRequestConfig<T>): Promise<T> {
  137. return this.request<T>({ ...config, method: 'POST' })
  138. }
  139. // 发送delete请求
  140. delete<T>(config: myRequestConfig<T>): Promise<T> {
  141. return this.request<T>({ ...config, method: 'DELETE' })
  142. }
  143. // 发送patch请求
  144. patch<T>(config: myRequestConfig<T>): Promise<T> {
  145. return this.request<T>({ ...config, method: 'PATCH' })
  146. }
  147. }
  148. export default YJLRequest

2、封装请求函数

image.png

  1. // 网络请求统一的出口
  2. // import yjlRequest from "@/service/"
  3. import YJLRequest from "@/service/request"
  4. /**
  5. * 自定义请求的实例
  6. */
  7. const yjlRequest = new YJLRequest({
  8. // 这里的类型是 myRequestConfig 类型
  9. baseURL:"/api",
  10. // hiddenSuccessMessage:true
  11. })
  12. // 可以定义多个请求实例,不同实例有不同的默认配置,很灵活
  13. // export const yjlRequest2 = new YJLRequest()
  14. export default yjlRequest

3、外部使用

  1. <script setup lang="ts">
  2. import yjlRequest from "@/network"
  3. /** 服务器返回的结果类型,自己根据实际情况定义 */
  4. interface DataType {
  5. path: string
  6. httpMethod: string
  7. headers: any
  8. queryStringParameters: any
  9. isBase64Encoded: boolean
  10. body: any
  11. }
  12. const testFun = () => {
  13. yjlRequest
  14. .get<DataType>({
  15. url: "/http/testFun"
  16. })
  17. .then((res) => {
  18. console.log(`res`, res)
  19. })
  20. }
  21. </script>

====================

拦截器

用于发送请求或者得到相应结果时拦截,进行对应的处理

拦截请求

1.用于改变本次请求的配置,用来满足接受服务器的要求

2.可以用于播放请求中的动画,如点击按钮后有个图标在转(拦截拦截,然后播放图标动画),有回应时停止转动(拦截回应,然后停止 播放动画)

3.某些请求,必须携带一些特殊的信息(比如登录的token)
例如打开页面,就会发送请求给服务器,此时拦截,判断是否登录了,如果没登录就跳转到登录页面;如果登录了就继续发送请求

4、请求失败时,可以显示失败的原因

  1. //拦截请求
  2. axios.interceptors.request.use(config => {
  3. //请求发送成功时,执行这里的代码
  4. //config指的是这次拦截的请求的配置config
  5. //拦截后,必须用return 把请求发回出去,否则就只光拦截了
  6. return config
  7. }, error => {
  8. //请求发送失败时,执行这里的代码
  9. });

拦截响应

1、可以对服务器回应的数据作基本的转化
2、响应失败时,可以显示失败的原因

  1. //响应拦截
  2. axios.interceptors.response.use(res => {
  3. //成功接收服务器回应时,执行这里的代码
  4. //config指的是这次拦截的请求返回结果的config
  5. //拦截后,必须用return 把请求发回出去,否则就只光拦截了
  6. //一般只需要返回data就可以了,其他的没什么用
  7. return res.data;
  8. }, error => {
  9. NProgress.done();
  10. return Promise.reject(new Error(error));
  11. })