Vue 在早期一直提供有一个官网的 ajax 请求框架 vue-resource,就好像我们在前面学习的 Vuex、vue-router 一样,都是属于 Vue 的官方框架。

为什么我们在这一章学习网络请求时会去介绍 axios 而不是 vue-resource 呢?因为 vue-resource 已经停止维护了!我们看一下犹大发布的这段声明。大概意思为:

vue-resource 虽然在 Vue 的官方组织之中,但是一直由 PageKit 团队进行维护,但是随着时间的推移,我们得出结论,Vue 并不真正需要“官方 ajax 库”,因为:与路由和状态管理不同,ajax 不是需要与 Vue 进行核心深度集成的问题领域。在大多数情况下,纯粹的第三方解决方案可以同样很好地解决问题。现在有了很好的第三方 ajax 库解决了这个问题,并且它更积极地改进和维护,所以 Vue 官方不再打算去继续维护 vue-resource,因为有了更好的方案。

这上面说的第三方 ajax 库就是 axios。现如今 Vue 官方也推荐使用 axios 来进行 Vue 中的 ajax 请求,所以我们在这一章就一起来学习一下 axios。

Axios

先来看一下 Axios 在 Github 上的描述:

Promise based HTTP client for the browser and node.js

这是一个基于 Promise 的 Http 客户端,并且可以用于浏览器和 node.js。我们知道 Promise 是 js 异步的一种解决方案,它最大的特性就是可以通过 .then 的方式来进行链式调用。下面通过一个实例来看一下 axios 的基本使用。

<script src="https://unpkg.com/axios/dist/axios.min.js"></script>

<div id="app">
    {{data}}
</div>

<script>
    var vm = new Vue({
        el: '#app',
        data: {
            data: ''
        },
        mounted() {
            var p = axios.get('./data.json');
            console.log(p); // Promise
            p.then((res) => {
                console.log(this);
                this.data = res;
            }).catch(function (err) {
                console.log(err);
            });
        },
    });
</script>

上面的代码通过 CDN 的方式引入了 axios:

<script src="https://unpkg.com/axios/dist/axios.min.js"></script>

然后通过 axios.get('./data.json') 方法进行了一个 get 请求,该请求返回一个 Promise 对象。我们把它赋值给变量 p,然后通过这个 Promise 对象进行 .then 操作,来进行获取数据之后的回调操作。

这就是使用 axios 进行的一个标准的 ajax 请求方式。当使用 axios 进行一个 ajax 请求时,无论是 get、post、put 等,它都会返回一个 Promise 对象,我们通过这个 Promise 对象进行 .then 的链式调用来执行数据请求之后的执行逻辑。

也就是说 axios 的核心使用就是这个 Promise 对象,就像作者对 axios 的简介一样。那么这样一个 Promise 有什么好处呢?

我们来看下面的这段需求:

我们需要根据用户来获取他的朋友们,并且通过列表把用户的朋友展示出来。现在服务器提供了两个接口:1、根据 ID 获取用户,2、根据用户获取用户的朋友。

我们通过 express 搭建了一个后台的服务,用以提供这两个接口:

router.post('/users', function(req, res, next) {
  if (req.body.id === '123') {
    res.send({
      name: 'LGD_Sunday',
      age: '26'
    });
  }
});

router.post('/users/friends', function(req, res, next) {
  res.send([
    {
      name: '张三',
      age: '28'
    },
    {
      name: '李四',
      age: '22'
    },
    {
      name: '王五',
      age: '30'
    }
  ]);
});

接下来就是前端的实现代码:

<div id="app">
  <ul>
    <li v-for="(friend, index) in friends" :key="index">{{friend.name}}</li>
  </ul>
</div>

<script>
    var vm = new Vue({
        el: '#app',
        data: {
            user: {},
            friends: []
        },
        mounted() {
            axios.post('/users', {
                id: '123'
            }).then((res) => {
              // 获取用户信息,执行我们的 赋值逻辑
              this.user = res.data;
            }).then((res) => {
              // 通过用户信息,调用下一个接口,并返回它的 Promise ,我们这里调用 /users/friends
              return axios.post('/users/friends', this.user);
            }).then ((res) => {
              // 获取 friends 信息,执行我们的 赋值逻辑....
              this.friends = res.data
            }).catch(function (err) {
                console.log(err);
            });
        },
    });
</script>

在上面的代码中,先通过 axios.post('/users',{ id: '123'}) 进行了第一次数据请求,获取到用户的信息,并赋值给 this.user,这是第一步操作。

然后通过 return axios.post('/users/friends', this.user); 进行第二次网络请求,并 return 返回的 Promise。

最后通过 this.friends = res.data 赋值 friends 数据。三个 then 方法把执行逻辑进行了分割,使逻辑变得更加清晰和可维护,其关键点就在于 axios 会返回一个 Promise 对象。就像作者对他的介绍:这是一个基于 Promise 的 Http 客户端,并且可以用于浏览器和 node.js

同样 Promise 所拥有的特性在 axios 上也都是可以使用的。比如我们可以同时执行多个 ajax 请求

axios.all([
  axios.post('/users', {
    id: '123'
  }),
  axios.post('/users/friends'),
]).then(axios.spread((usersData, friendsData) => {
  this.user = usersData.data;
  this.friends = friendsData.data
})).catch((err) => {

});

同样我们也可以直接通过 axios 来进行配置请求:

axios({
  method: 'post',
  url: '/users/friends',
  data: {}
}).then((res) => {
  this.friends = res.data
});

然后来看一下 axios 的所有配置信息(数据来自 axios github):

{
  // url 是将用于请求的服务器 URL
  url: '/user',

  // method 是发出请求时使用的请求方法
  method: 'get', // default

  // 基础 URL 路径,假如 url 不是绝对路径,如http://127.0.0.1:3000/users/friends,
  // 那么向服务器发送请求的URL将会是 baseURL + url。
  baseURL: 'https://some-domain.com/api/',

  //transformRequest 允许在将请求数据发送到服务器之前对其进行更改
  // 这仅适用于请求方法'PUT','POST'和'PATCH'
  // 数组中的最后一个函数必须返回一个字符串或 Buffer,ArrayBuffer,FormData 或 Stream 的实例
  transformRequest: [function (data, headers) {
    // Do whatever you want to transform the data

    return data;
  }],

  // transformResponse 方法允许在数据传递到 then/catch 之前修改 response 数据。此方法最后也要返回数据。
  transformResponse: [function (data) {
    // Do whatever you want to transform the data

    return data;
  }],

  // 发送自定义 Headers 头文件,头文件中包含了 http 请求的各种信息。
  headers: {'X-Requested-With': 'XMLHttpRequest'},

  // params 是与请求一起发送的 URL 参数
  // 必须是普通对象或 URLSearchParams 对象
  params: {
    ID: 12345
  },

  // paramsSerializer 是一个可选函数,负责序列化 params
  paramsSerializer: function(params) {
    return Qs.stringify(params, {arrayFormat: 'brackets'})
  },

   // data 是要作为请求体发送的数据
   // 仅适用于请求方法 'PUT','POST'和'PATCH'
   // 如果没有设置 transformRequest,则必须是以下类型之一:
   // - 字符串,普通对象,ArrayBuffer,ArrayBufferView,URLSearchParams
   // - 仅限浏览器:FormData,File,Blob
   // - 仅限节点:流,缓冲区
  data: {
    firstName: 'Fred'
  },

  // timeout 指定请求超时之前的毫秒数。
  // 如果请求的时间超过“超时”,请求将被中止。
  timeout: 1000, // default is `0` (no timeout)

  // 表明是否有跨域请求需要用到证书
  withCredentials: false, // default

  // adapter 允许自定义处理请求,使测试更容易。
  // 返回一个 promise 并提供一个有效的响应
  adapter: function (config) {
    /* ... */
  },

  // auth 表示提供凭证用于完成 http 的身份验证
  // 这将设置一个 Authorization 信息,覆盖任何现有信息
  // 使用 headers 设置的 Authorization 自定义信息。
  auth: {
    username: 'janedoe',
    password: 's00pers3cret'
  },

  // responseType 表示服务器将响应的数据类型
  // 选项是'arraybuffer','blob','document','json','text','stream'
  responseType: 'json', // default

  // responseEncoding 表示用于解码响应的编码
  //  注意他将忽略“stream”或“客户端”请求的“responseType”
  responseEncoding: 'utf8', // default

  // xsrfCookieName 是用作xsrf令牌值的cookie的名称
  xsrfCookieName: 'XSRF-TOKEN', // default

  // xsrfHeaderName 是带有 xsrf 标记值的 http 标头的名称
  xsrfHeaderName: 'X-XSRF-TOKEN', // default

  // onUploadProgress 允许处理上传的进度事件
  onUploadProgress: function (progressEvent) {
    // Do whatever you want with the native progress event
  },

  // onDownloadProgress 允许处理下载的进度事件
  onDownloadProgress: function (progressEvent) {
    // Do whatever you want with the native progress event
  },

  // maxContentLength 定义了允许的以字节为单位的 http 响应内容的最大大小
  maxContentLength: 2000,

  // validateStatus 定义了根据 HTTP 响应状态码决定是否接收或拒绝获取到的 promise。
  // 如果 validateStatus 返回 true (或为 null 或 undefined),promise 将被接收;否则 promise 将被拒绝。
  validateStatus: function (status) {
    return status >= 200 && status < 300; // default
  },

  // maxRedirects 定义了 node.js 中要遵循的最大重定向数。
  // 如果设置为 0,则不会执行重定向。
  maxRedirects: 5, // default

  // httpAgent 和 httpsAgent 定义了执行 http 时要使用的自定义代理
  httpAgent: new http.Agent({ keepAlive: true }),
  httpsAgent: new https.Agent({ keepAlive: true }),

  // 'proxy'定义代理服务器的主机名和端口。使用 auth 来进行身份验证
  proxy: {
    host: '127.0.0.1',
    port: 9000,
    auth: {
      username: 'mikeymike',
      password: 'rapunz3l'
    }
  },

  // cancelToken 指定可用于取消请求的取消令牌
  cancelToken: new CancelToken(function (cancel) {
  })
}

axios 的使用比较简单,其最核心的概念就是对 Promise 的应用,就像作者说的:这是一个基于 Promise 的 Http 客户端,并且可以用于浏览器和 node.js。关于 axios 在实际项目中的应用还有一些小的技巧,比如对统一的请求处理、原型设置等等,我们会在最后实例解析的时候为大家讲解。

发表评论

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