TOC

网络请求

    在真实的项目开发中,实际上很少使用JavaScript原生的XMLHttpRequest或浏览器提供的fetch方法去完成网络请求,因为原生的网络请求过于底层,换句话说,就是过于简单,并不一定适用我们的应用场景,如果真正想要在项目中使用它,还需要为其进行进一步的封装;
    此外,JavaScript有两个运行环境,第一个为浏览器、第二个就是Node,那么如果使用原XMLHttpRequest或者浏览器的fetch方法来发送网络请求,我们所编写的这样的fetch代码,在浏览器中确实是可以正常使用的,但是如果我们希望在Node当中来运行,是没有办法实现的,Node是没有fetch对象的,所以在这种场景下,就必须换方案,也就是说,同一套代码在浏览器能运行,可能在Node当中就没法运行;
    那么为了解决这种问题,一些第三方的网络请求框架油然而生,这种框架就完全解决了这些问题,框架会在内部直接解决运行环境带来的适配问题,同时,它还额外提供了很多常用的一些新功能,所以对于网络请求来说,一般都会借助第三方比较成熟都一些网络请求库;

Axios库

    其实,在Vue早起,Vue官方团队有专门封装一个网络请求的库,即vue-resource,也就是在Vue框架里面,可以使用vue-resource来实现网络请求,但是在2016年时,Vue官方宣称,vue-resource库不再是Vue框架推荐的网络请求库了,并停止了该项目的维护,官方推文建议使用Axios来代替原有的vue-resource;
    Axios在浏览器中,是通过JavaScript原生的XMLHttpRequest来实现的,在Node当中,使用的是NodeJS的http模块来实现的,也就意味着,Axios库已经同时兼容了浏览器和Node两个环境,并且,Axios也提供了对Promise的支持,对于一个axios对象对象来讲,它的返回值就是一个Promise对象,可以通过then或者catch拿到这个请求返回的结果或者监听它的错误;
    同时,Axios支持拦截请求和响应,我们可以为每一次请求都添加一个拦截器,在请求之前或者之后,做一些数据处理的操作;
Axios安装
    对于Axios的安装也非常的简单,直接在项目目录下使用npm进行安装即可,目前的版本为1.1.3,如下示例;
[cce@doorta /usr/local/Project/front]# npm install axios

Axios请求类型

    Axios支持HTTP协议当中大多数常见的请求类型,每种类型都有提供一个独立的方法来实现,如下,这就是Axios框架内已知实现的请求类型的方法;
axios(config):直接使用axios对象来发送各类网络请求;
axios.request(config):使用axios对象的request方法来发送网络请求;
axios.get(config):使用axios对象的get方法来发送GET请求;
axios.delete(config):使用axios对象的delete方法来发送DELETE请求;
axios.head(config):使用axios对象的head方法来发送HEAD请求;
axios.post(config):使用axios对象的post方法来发送POST请求;
axios.put(config):使用axios对象的put方法来发送PUT请求;
axios.patch(config):使用axios对象的patch来发送PATCH请求;
axios.all([]):使用axios对象的all方法,同时发送多个网络请求,它接收一个数组,数组内是一个一个axios请求对象,并且只有数组内所有的axios对象请求成功之后,才会调用resolve函数,实际上它内部就是调用了一个Promise.all方法;
    每一个axios对象都有一个config配置对象,在这个config对象内,我们可以定义在网络请求中,常用的一些参数,如headers、params等,那么常用的方法大致有如下几项;
url:请求的URI路径;
method:请求的method类型;
baseURL:请求的根路径,它会直接和url属性进行拼接;
transformRequest:请求拦截器,对一个请求报文在发出之前的钩子函数;
transformResponse:响应拦截器,对一个响应报文在返回之后的钩子函数;
headers:该属性为一个对象,对象内是一些自定义的请求头的设置;
params:URL请求参数,该属性为一个对象,对象内的属性和值,都会拼接到URL上;
paramsSerializer:查询对象序列化函数;
data:请求的body部分,即向服务端提交的数据;
timeout:设置超时时长;

Axios基础使用

    如果希望在Vue框架内,使用Axios来实现网络请求,首先,需要使用import语法在Axios包中拿到一个axios对象,该对象本身就可以实现Axios内部所有的网络请求类型,具体请求为哪种类型,可以使用method来指定,所以,我们可以直接利用这个axios对象直接发送网络请求;
    axios对象需要接收一个参数,该参数是一个对象,对象内就是需要进行Axios网络请求的配置和参数,如method、headers等属性的配置,同时,axios对象的返回值,就是一个Promise对象,也就是说我们可以直接利用这个axios对象返回结果进行进一步处理,如下示例;
<template>
  <div>
    <button v-on:click="start_request">发起网络请求</button>
  </div>
</template>
<script setup>
import axios from 'axios'

function start_request() {
  axios({
    url: "http://127.0.0.1:8000/get_data",  // 指定请求的URL
    method: "GET"  // 指定请求的method
  }).then(res => console.log(res.data)).catch(err => console.log(err))
}
</script>

扩展一
    Axios库,还单独为每一种类型的请求,单独封装了一个方法,如GET、POST、DELETE、PUT等,这些方法都在axios对象下,我们可以将不同的请求类型来单独调用对应的方法,这些方法都接收两个参数,第一个参数为请求的URL地址,第二个参数为请求的配置和参数,如下示例;
<template>
  <div>
    <button v-on:click="get_request">发起GET请求</button>
    <button v-on:click="post_request">发起POST请求</button>
  </div>
</template>
<script setup>
import axios from 'axios'

function get_request() {
  axios.get('http://127.0.0.1:8000/get_data', {}
  ).then(res => console.log(res.data)).catch(err => console.log(err))
}
function post_request() {
  axios.post('http://127.0.0.1:8000/get_data/', {
        data: {"name": "cce", age: 18}
      }
  ).then(res => console.log(res.data)).catch(err => console.log(err))
}
</script>

扩展二
    如果我们希望同时发送多个网络请求,并且只有这多个请求同时成功时,才调用对应的回调函数,那么我们可以只有axios对象下面的all()方法,它接收一个数组,该数组内的元素,就是已封装好的axios请求对象,如下示例;
<template>
  <div>
    <button v-on:click="get_request">发起GET请求</button>
  </div>
</template>
<script setup>
import axios from 'axios'

axios.defaults.timeout = 1000;
axios.defaults.baseURL = 'http://127.0.0.1:8000';

function get_request() {
  axios.all([
    axios.get('/get_data/'),
    axios.get('/get_data/')
  ]).then(res => console.log(res)).catch(err => console.log(err))
}
</script>

源码解析
    因为axios、axios.get、axios.post等,这些对象的返回值就是一个Promise对象,所以对于axios.all()方法来讲,它的本质,就是将这多个axios对象,交给Promise.all()方法来处理,如下源码;
// Expose all/spread
axios.all = function all(promises) {
    return Promise.all(promises)
}

Axios初始配置

    在正式使用Axios之前,其实我们可以对Axios进行一些初始化配置,这样可以使得我们在项目开发的过程中更加的敏捷,在axios对象内有一个defaults对象,该对象是axios的默认实例(axios可以定义多个实例)对象,在这个defaluts属性下,对象内有众多的参数,这些参数就是用来定义defaults实例下面的初始化配置的,我们可以直接使用对象赋值的方式来重新设定这些初始化配置;
    那么常用的配置主要有三个即,baseURL、timeout、headers,其中baseURL主要用来定义根路径的,所谓根路径就是后端项目的URL根地址,并非具体的接口路径,timeout属性,主要用来设定请求的超时间,而headers属性是一个对象,它的主要作用就是自定义请求头,可以使用headers属性预先定义一些请求头,那么在后期开发的时候,就无需多次重复定义headers了,如下示例;
<template>
  <div>
    <button v-on:click="get_request">发起GET请求</button>
  </div>
</template>
<script setup>
import axios from 'axios'

axios.defaults.timeout = 1000;
axios.defaults.baseURL = 'http://127.0.0.1:8000';
axios.defaults.headers = {};

function get_request() {
  axios.get('/get_data/').then(res => console.log(res.data)).catch(err => console.log(err))
}
</script>

Axios多实例

    其实在上述的初始化配置中也提到过,默认情况下Axios会有一个defaults的实例,在实际的开发中,可能会存在多实例的可能,比如当我们的项目中可能会引用到第三方的API,那么此时,我们可能会使用两个Axios实例来实现,默认Axios实例用来请求本项目的后端服务器,另一个新的实例用来请求第三方的API接口,这两个实例之间都定义了不同的baseURL、headers属性;
    那么想要创建一个新的Axios实例,我们只需要调用axios对象的create()方法即可,它就会返回一个新的axios实例,那么在创建这个实例的同时,我们也可以传递一些初始化配置,比如baseURL、headers及timeout等属性,如下示例;
import axios from 'axios'

const instance1 = axios.create({
  baseURL: "http://127.0.0.1:8000",
  headers: {},
  timeout: 1000
})
const instance2 = axios.create({
  baseURL: "http://127.0.0.1:8080",
  headers: {},
  timeout: 1000
})
    那么当我们多实例创建完成之后,我们就可以直接使用对应的实例来进行网络请求了,它的使用方法和默认示例是一样的,但是经过测试,新创建的示例,没有all()方法,如下示例;
instance1.get('/get_data/').then(res => console.log(res))

Axios拦截器

    在Axios框架中,提供了一个拦截器的功能,其中,拦截器又分请求拦截器和响应拦截器,这两个拦截器都在axios对象下的interceptors对象内,interceptors对象内的request对象为请求拦截器,interceptors对象内的response对象为响应拦截器,这两个对象内都有一个use方法,该方法的主要作用就是来定义拦截器的;
请求拦截器
    请求拦截器在axios对象下的interceptors.request下,可以调用该对象的use方法来定义具体的请求拦截器,use方法接收两个参数,第一个参数为正式发起请求之前回调的函数,第二个参数为请求失败调用的回调函数;
    正式发起请求之前回调的函数和请求失败的函数,他们都会默认会接收一个参数,即此次请求的config,那么对于请求之前,我们可以拿到这个config,做一些修改,比如,新增一个header请求头,传入认证Token,等等功能,那么对于失败回调函数的config参数,我们可以记录此次配置,用作问题的排查,如下示例;
<template>
  <div>
  </div>
</template>
<script setup>
import axios from 'axios'

axios.interceptors.request.use( // 定义请求拦截器
    (config) => {  // 定义在正式发起请求之前的回调函数
      console.log(config)
      config.headers['describe'] = 'Test the interceptor'
      return config
    },
    (config) => {  // 定义请求失败时的回调函数
      console.log("请求失败", config)
    })

axios.get('http://127.0.0.1:8000/get_data/').then(res => console.log(res)).catch(err => console.log(err))
</script>

应用场景
    对于请求拦截器来讲,一个非常典型的应用场景,在数据开始请求之前,页面可以播放loading动画,那么当响应成功之后,可以取消这个loading状态;
响应拦截器
    响应拦截器在axios对象下的interceptors.response下,同样的,可以调用该对象的use方法来定义具体的响应拦截器,响应拦截器的use方法接收两个参数,第一个参数为响应成功的回调函数,第二个参数为响应失败调用的回调函数;
    响应成功的回调函数默认会接收一个参数,该参数为响应的数据,而响应失败的回调函数,默认也会接收到一个参数,即具体失败的错误信息,如下示例;
<template>
  <div>
  </div>
</template>
<script setup>
import axios from 'axios'

axios.interceptors.response.use( // 定义响应拦截器
    (res) => {  // 定义响应成功时的回调函数
      console.log('请求成功', res)
    },
    (err) => {  // 定义响应失败时的回调函数
      console.log("请求失败", err)
    })


axios.get('http://127.0.0.1:8000/get_data/').then(res => console.log(res)).catch(err => console.log(err))
</script>

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注