axios网络请求


axios ⽹络请求

1.axios 简单介绍

⼀、本节⼤纲

  • 前端 ajax 框架选型
  • axios 的简介及优势

⼆、前端 ajax 框架选

在 ajax 最开始出现的时候,使⽤原⽣的 XMLHTTPRequest 进⾏ ajax 请求的操作,这种⽅式⽐较麻烦,浏览器兼容性各种问题都需要⾃⼰去处理,所以我们暂时不去讨论原⽣的 XMLHTTPRequest 的这种⽅ 法。

  • jquery 的出现对前端开发产⽣了⽐较深远的影响。jquery 是⼀个相对完整的基于 DOM 的前端 js 框架,ajax ⽹络请求只是其中的⼀个模块,并且⽅便易⽤。但是随着新⼀代的前端框架 vue、 ReactJs、AngularJS 的兴起,Jquery 的路也越来越窄,jquery ajax 的替代品也越来越多,其中不乏⼀些设计精良、使⽤⽅便的 ajax ⽹络处理类库。如:本节为⼤家介绍的 axios。
  • 在 vue1.x 的版本中,曾经有⼀个⽹络请求处理的模块 vue-resource,短⼩精悍,⽐ Jquery 要⼩很多。 但是从 vue2.0 开始,vue 作者尤⾬溪就宣布不再对 vue-resource 进⾏维护了,所以不建议⼤家继续使⽤。
  • 在⼤神尤⾬溪宣布不再对 vue-resource 进⾏维护的同时,向⼴⼤的 Vue 开发者推荐了⼀个⾮常优秀的 ajax ⽹络请求处理库 axios。
  • axios 本身并不属于 vue 范畴,但是属于前端⽣态圈特别重要的 HTTP ⼯具类库,由于 Vue 作者的推荐,在 Vue 项⽬中应⽤尤其⼴泛。

三、axios 的简介及优势

基于 Promise 的,⽤在浏览器和 nodeJS 环境下的 HTTP 客户端。( Promise based HTTP client for the browser and node.js )

  • ⽀持从浏览器中创建XMLHttpRequests
  • ⽀持从 node.js 创建 http 请求(这个是其他框架不具备的)
  • ⽀持 PromiseAPI(最重要特点)
  • ⽀持拦截器,拦截请求和响应(核⼼功能)
  • ⽀持转换请求数据和响应数据(核⼼功能)
  • ⾃动转换 JSON 数据(核⼼功能)
  • 客户端⽀持防御 XSRF 攻击

⽀持多种请求⽅法

  • request(config)
  • get(url[, config])
  • delete(url[, config])
  • head(url[, config])
  • post(url[, data[, config]])
  • put(url[, data[, config]])
  • patch(url[, data[, config]])

浏览器兼容性

2.axios 的基本⽤法

⼀、本节⼤纲

  • 安装使⽤ axios
  • axios 发送 GET 请求
  • axios 发送 POST 请求
  • axios 发送并⾏请求

⼆、安装使⽤ axios

代码⽂件引⽤⽅式

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

npm 安装⽅式

npm install axios

yarn 安装⽅式

yarn add axios

在 Vue 项⽬中引⼊ axios 模块

import axios from "axios";

三、axios 发送 GET 请求

在使⽤ axios 发送 HTTP 请求之前,介绍⼀个⽹站:http://httpbin.org

这个⽹站提供了免费的 HTTP 请求及相应服务,我们可以利⽤这个服务测试我们的 axios。

//使⽤axios发送get请求
axios({
  method: "get", //http请求⽅法
  url: "http://httpbin.org/get?param=hello", //http服务地址
})
  .then(function (response) {
    //请求成功响应结果response
    console.log(response);
  })
  .catch(function (error) {
    //请求异常响应结果
    console.log(error);
  });
//HTTP GET⽅法请求可以简写如下:
axios
  .get("http://httpbin.org/get?param=hello")
  .then(function (response) {
    console.log(response);
  })
  .catch(function (error) {
    console.log(error);
  });
  • 使⽤ axios(config) 发送 http 请求,config 为该请求的配置信息对象
  • axios.get 等同于 axios 使⽤ method:get
  • axios 是基于 Promise 的 HTTP 客户端,所以可以使⽤ then、catch 对请求结果进⾏处理
  • 如果不习惯在 URL 参数上直接传递参数,可以使⽤ axios 的 config :params 传递参数。如下所示:
// 上⾯的GET请求也可以通过下⾯的⽅式传参
axios
  .get("http://httpbin.org/get", {
    params: {
      param: "hello",
    },
  })
  .then(function (response) {
    console.log(response);
  })
  .catch(function (error) {
    console.log(error);
  });

四、axios 发送 POST 请求

axios 发送 HTTP post 请求的基本⽅法如下:

axios({
  method: "post", //请求⽅法
  url: "http://httpbin.org/post", //请求服务地址
  data: {
    firstName: "zhang",
    lastName: "san",
  },
});
//省略then、catch等请求结果处理代码,参考GET⽅法即可。
  • post 请求使⽤ data 传递参数,特别注意和 GET ⽅法不⼀样。
  • HTTP POST 请求的简写⽅法如下:
axios.post("http://httpbin.org/post", {
  firstName: "zhang",
  lastName: "san",
});
//省略then、catch

五、axios 发送并⾏请求

在有些情况下,我们希望某些异步⽹络请求结果处理有⼀定的顺序。⽐如,有 getHello() 和 getWorld() 两个异步操作,我们希望将两个 HTTP 的请求都完成之后,结果合并处理或者进⾏下⼀步操作。为此 axios 为我们提供了 axios.all ⽅法执⾏并发的异步⽹络请求操作,将响应结果统⼀处理。

function getHello() {
  return axios.get("http://httpbin.org/get?param=hello");
}
function getWorld() {
  return axios.get("http://httpbin.org/get?param=world");
}
axios.all([getHello(), getWorld()]).then(
  axios.spread(function (res1, res2) {
    // 两个请求都执⾏完成后,进⼊该函数
    console.log(res1.data.args.param + " " + res2.data.args.param);
  })
);

浏览器⽇志的打印结果如下:

hello world

上⾯的 axios.all 函数还可以写成如下的形式,返回值是⼀个数组。然后通过数组下标获取响应结果数据。results[0] 代表第⼀个 getHello() 函数的请求结果,results[1] 代表第⼆个 getWorld() 函数的请求结 果。

axios.all([getHello(), getWorld()]).then(function (results) {
  console.log(results[0].data.args.param + " " + results[1].data.args.param);
});

所以 axios.spread 函数实际的作⽤就是将返回值数组,展开为多个返回值,解构赋值。

3.axios 的配置详解

⼀、本节⼤纲

  • 常⽤数据格式
  • 数据的转换
  • ⽂件上传与下载进度
  • axios 请求配置
  • axios 响应数据结构
  • axios 全局配置

⼆、常⽤数据格式

在实际的开发过程中,服务端接收数据的⽅式可能是多种数据格式的,⽐如:JSON、QueryString 表单数据等形式。

2.1.JSON 数据格式

当 data 参数是 JSON 对象的时候,默认的 Content-Type 是 application/json 。所以下⾯代码中的 headers 的 content-type 设置可以省略。

axios
  .post(
    "http://httpbin.org/post",
    {
      firstName: "zhang",
      lastName: "san",
    },
    {
      headers: {
        "Content-Type": "application/json",
      },
    }
  )
  .then(function (response) {
    console.log(response);
  });

axios 的 post 请求⽅法三个参数分别是:url 请求地址,data 数据,config 配置。

2.2.表单数据格式

如果服务端不接收 JSON 对象数据,⽽是接收表单数据,那么我们该如何调整上⾯的代码?

  • ⾸先我们需要将 JSON 对象转换为 QueryString 字符串,使⽤ qs.stringify() 函数

    • 命令⾏输⼊:npm install qs
    • 安装完成后在需要⽤到的代码中:import qs from 'qs'
    • qs.parse() 是将 URL 解析成对象的形式, qs.stringify() 是将对象序列化成 URL 的形式,以 & 进⾏拼接
  • 当 data 参数是字符串的时候,默认的 Content-Type 是 application/x-www-form-urlencoded 。所以下⾯代码中的 headers 的 content-type 设置可以省略

axios
  .post(
    "http://httpbin.org/post",
    qs.stringify({
      firstName: "zhang",
      lastName: "san",
    }),
    {
      headers: {
        "content-type": "application/x-www-form-urlencoded",
      },
    }
  )
  .then(function (response) {
    console.log(response);
  });

控制台可以看到,显示数据是以表单 form 的⽅式提交的。

三、数据的转换

除了常⽤的表单数据格式、JSON 数据格式,实际开发中还有很多的数据格式、内容需要进⾏处理。 ⽐如我们希望对发送出去的数据做特殊的⾃定义处理,axios 也为我们提供了⽅法。

  • transfromRequest ⽤于在向服务端发送请求之前,将数据做处理修改请求数据。该⽅法只对 PUT、 POST、PATCH 请求⽣效。⽽且,此⽅法最后必须返回⼀个 string、ArrayBuffer 或者 Stream。
  • transformResponse 对响应结果数据,进⾏转换处理。收到响应之后,then/catch 之前做数据转换处理⼯作。
{
  transformRequest: [function (data) {
    // 在这⾥对 data 进⾏任意转换处理
    return data;
 }],
  // `transformResponse` 在传递给 then/catch 前,允许修改响应数据
  transformResponse: [function (data) {
    // 在这⾥对 data 进⾏任意转换处理
    return data;
 }]
}

四、⽂件上传与下载进度

使⽤如下⽅法可以将⽂件下载,此处并未对下载⽂件做额外处理,主要介绍⼀下配置函数。 progress.loaded 表示已经加载的进度,progress.total 表示需要加载的总量。

axios({
  url: "https://niit-soft.oss-cn-hangzhou.aliyuncs.com/mp4/1.mp4",
  method: "get",
  onDownloadProgress(progress) {
    console.log(Math.round((progress.loaded / progress.total) * 100) + "%");
  },
});

axios 不仅可以获取下载的进度,还可以获取上传的进度。

// `onUploadProgress` 允许为上传处理进度事件
  onUploadProgress: function (progressEvent) {
    // 对原⽣进度事件的处理
 },

五、axios 请求配置

我们已经学习了最基本的请求⽅法 GET、POST 的使⽤,PUT、DELETE 请求的⽅法和 POST 请求使⽤⽅法是基本⼀致的。如果没有指定 method,请求将默认使⽤ get ⽅法。此外,url 是必需的请求参数。 下⾯是其他的请求参数:

{
  // `url` 是⽤于请求的服务器 URL(必填)
  url: '/user',
  // `method` 是HTTP请求时使⽤的⽅法, 默认是 get
  method: 'get',
  // `baseURL` 将⾃动加在 `url` 前⾯,除⾮ `url` 是⼀个绝对 URL。
  // 它可以通过设置⼀个 `baseURL` 便于为 axios 实例的⽅法传递相对 URL
  baseURL: 'https://some-domain.com/api/',
  // `headers` 是即将被发送的⾃定义请求头
  headers: {'X-Requested-With': 'XMLHttpRequest'},
  // `params` 是即将与请求⼀起发送的 URL 参数
  // 必须是⼀个⽆格式对象(plain object)或 URLSearchParams 对象
  params: {
    ID: 12345
 },
  // `paramsSerializer` 是⼀个负责 `params` 序列化的函数。
  //针对params的参数序列化通常axios⾃动完成,所以并不常⽤
  paramsSerializer: function(params) {
    return qs.stringify(params, {arrayFormat: 'brackets'})
 },
  // `data` 是作为请求body被发送的数据,只适⽤于这些请求⽅法 'PUT', 'POST', 和 'PATCH'
  // 在没有设置 `transformRequest` 时,data数据必须是以下类型之⼀:
  // - string, plain object, ArrayBuffer, ArrayBufferView, URLSearchParams
  // - 浏览器专属:FormData, File, Blob
  // - Node 专属: Stream
  data: {
    firstName: 'Fred'
 },
  // `timeout` 指定请求超时的毫秒数(0 表示⽆超时时间)
  // 如果请求话费了超过 `timeout` 的时间,请求将被中断
  timeout: 1000,
  // `withCredentials` 表示跨域请求时是否需要使⽤凭证
  withCredentials: false, // 默认的
  // `adapter` 允许⾃定义处理请求,使⽤mock⽅式⽅便测试
  // 返回⼀个 promise 并应⽤⼀个有效的响应
  adapter: function (config) {
    /* ... */
 },
  // `auth` 表示应该使⽤ HTTP 基础验证,并提供凭据
  // 这将设置⼀个 `Authorization` 头,可以对应Http Basic基础认证模式。
  //如果是java开发⼈员,可以简单的学⼀下Spring Security的Http Basic基础认证模式,就会理解。
  auth: {
    username: 'janedoe',
    password: 's00pers3cret'
 },
  // `responseType` 表示服务器响应的数据类型,可以是 'arraybuffer', 'blob', 'document', 'json', 'text', 'stream'
  responseType: 'json', // 默认的
  //以下两个配置与跨站攻击伪造相关的防御,须与服务端名称保持⼀致。
  // `xsrfCookieName` 是⽤作 xsrf token 的值的cookie的名称
  xsrfCookieName: 'XSRF-TOKEN', // default
  // `xsrfHeaderName` 是承载 xsrf token 的值的 HTTP 头的名称
  xsrfHeaderName: 'X-XSRF-TOKEN', // 默认的
  // `maxContentLength` 定义允许的响应内容的最⼤尺⼨
  maxContentLength: 2000,
  // `validateStatus` 定义对于给定的HTTP 响应状态码是 resolve 或 reject promise 。如果 `validateStatus` 返回 `true` (或者设置为 `null` 或 `undefined`),promise 将被 resolve; 否则,promise 将被 rejecte
  validateStatus: function (status) {
    return status >= 200 && status < 300; // 默认的
 },
  // `maxRedirects` 定义在 node.js 中 follow 的最⼤重定向数⽬
  // 如果设置为0,将不会 follow 任何重定向
  maxRedirects: 5, // 默认的
  // `httpAgent` 和 `httpsAgent` 分别在 node.js 中⽤于定义在执⾏ http 和 https 时使⽤的⾃定义代理。允许像这样配置选项:
  // `keepAlive` 默认没有启⽤
  httpAgent: new http.Agent({ keepAlive: true }),
  httpsAgent: new https.Agent({ keepAlive: true }),
  // 'proxy' 定义代理服务器的主机名称和端⼝
  // `auth` 表示 HTTP 基础验证应当⽤于连接代理,并提供凭据
  // 这将会设置⼀个 `Proxy-Authorization` 头,覆写掉已有的通过使⽤ `header` 设置的⾃定义 `Proxy-Authorization` 头。
  proxy: {
    host: '127.0.0.1',
    port: 9000,
    auth: : {
      username: 'mikeymike',
      password: 'rapunz3l'
   }
 },
  // `cancelToken` 指定⽤于取消请求的 cancel token
  cancelToken: new CancelToken(function (cancel) {
 })
}

六、axios 响应数据结构

axios 请求的响应数据结构包含以下信息

{
  // `data` 由服务器提供的响应
  data: {},
  // `status` 来⾃服务器响应的 HTTP 状态码
  status: 200,
  // `statusText` 来⾃服务器响应的 HTTP 状态信息
  statusText: 'OK',
  // `headers` 服务器响应的头
  headers: {},
  // `config` 是为请求提供的配置信息
  config: {}
}

使⽤ then 时,将接收下⾯这样的响应:

axios.get("/user/12345").then(function (response) {
  console.log(response.data);
  console.log(response.status);
  console.log(response.statusText);
  console.log(response.headers);
  console.log(response.config);
});

五、axios 全局配置

之前所有的配置都是针对单次请求或者某个 api 请求的配置,在实际的开发中请求配置都是⼤部分⼀致, ⼩部分个性化的。针对⼤部分⼀致的内容,我们可以采⽤全局配置。

⽐如:

  • 请求服务端根地址 baseURL ,通常是很多 api 使⽤⼀个跟地址提供服务。
  • Authorization 的⽤户名密码信息等,不需要每次请求都进⾏设置。
  • timeout 请求超时时间,也不需要每次请求都单独设置等等。

下⾯的代码就是进⾏全局设置的⽅式。

axios.defaults.baseURL = "https://api.example.com";
axios.defaults.headers.common["Authorization"] = AUTH_TOKEN;

配置的优先级

当 defaults 全局配置与局部 config 配置发⽣冲突的时候,局部 config 配置的优先级要⾼于全局配置。

4.axios 的实例与拦截器

⼀、本节⼤纲

  • axios 多实例的必要性
  • 创建 axios 实例
  • axios 拦截器

⼆、axios 多实例的必要性

之前所有的配置都是针对默认实例的。但是在现实的开发中,我们通常不会去修改默认实例的配置,因为⾯向的后端服务可能是很多个,每⼀个后端服务 HTTP 请求的地址,请求超时的时间限制等都不⼀样,API 服务的鉴权的⽅式也有可能有所区别。

如上图中所示,我们通常根据请求不同的服务主体,创建多个 axios 实例。⽐如:

  • 为“系统管理”类的 API 服务创建⼀个 axios 实例
  • 为“业务数据”操作类 API 服务创建⼀个 axios 实例

这样做实际上是⼀种⼯程化的思想,将医⽣组织在⼀起就可以形成医院。但是我们不会把所有的医⽣放在⼀个医院⾥⾯,这样不利于应⽤,也不利于管理。我们会把医院分类,这样有利于对实例精细化管理和建设改造。

三、 创建 axios 实例

// 创建实例时设置配置的默认值
var instance = axios.create({
  baseURL: "http://httpbin.org",
});
// 在实例已创建后修改默认值
instance.defaults.headers.common["Authorization"] = AUTH_TOKEN;

四、axios 拦截

axios 的拦截器的作⽤就是针对所有请求和响应做拦截,所谓的拦截就是统⼀修改请求或响应的内容、参数、配置等信息。⽐如:

  • 在结合 JWT 令牌进⾏开发的时候,我们需要为每⼀个请求加上 JWT 令牌,这样服务端才能正确的授权访问。
  • 在 http 请求没有成功连接到服务端的时候我们通常做⼀个统⼀的异常处理。等等

如下是⼀个典型的拦截器逻辑的实现。

// request拦截器
instance.interceptors.request.use(
  (config) => {
    // 根据条件加⼊token-安全携带
    if (true) {
      // 需⾃定义
      // 让每个请求携带token
      config.headers["JWT-Token"] = "";
    }
    return config;
  },
  (error) => {
    // 请求错误处理
    return Promise.reject(error);
  }
);
// respone拦截器
instance.interceptors.response.use(
  (response) => {
    // 统⼀处理状态
    const res = response.data;
    if (res.statuscode != 1) {
      // 需⾃定义
      // 返回异常
      return Promise.reject({
        status: res.statuscode,
        message: res.message,
      });
    } else {
      return response.data;
    }
  },
  // 处理处理
  (error) => {
    if (error && error.response) {
      switch (error.response.status) {
        case 400:
          error.message = "错误请求";
          break;
        case 401:
          error.message = "未授权,请重新登录";
          break;
        case 403:
          error.message = "拒绝访问";
          break;
        case 404:
          error.message = "请求错误,未找到该资源";
          break;
        case 405:
          error.message = "请求⽅法未允许";
          break;
        case 408:
          error.message = "请求超时";
          break;
        case 500:
          error.message = "服务器端出错";
          break;
        case 501:
          error.message = "⽹络未实现";
          break;
        case 502:
          error.message = "⽹络错误";
          break;
        case 503:
          error.message = "服务不可⽤";
          break;
        case 504:
          error.message = "⽹络超时";
          break;
        case 505:
          error.message = "http版本不⽀持该请求";
          break;
        default:
          error.message = `未知错误${error.response.status}`;
      }
    } else {
      error.message = "连接到服务器失败";
    }
    return Promise.reject(error);
  }
);

文章作者: Syhan
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Syhan !
评论
  目录