Axios 学习总结

本贴最后更新于 1999 天前,其中的信息可能已经时移世易

一、第 1 章简介

1.1Axios 是什么?

Axios 是一个基于 promise 的 HTTP 库,类似 jquery 中的 ajax
它可以用于浏览器和 node.js 中

1.2Axios 有哪些特性?
  • 支持 Promise API
  • 拦截请求和相应
  • 转换请求数据和相应数据
  • 取消请求
  • 自动转换 JSON 数据
  • 客户端支持防御 XSRF
1.3Aixos 浏览器支持
  • FireFox 65+
  • Chrome 72+
  • IE 8+
  • Edge
  • Safari 9+

二、第 2 章 Axios 方法的基本使用

2.1 vue 项目的创建
#安装vue脚手架 npm install -g @vue/cli #通过脚手架创建一个vue项目 vue create axios-vue 回车 选择自定义安装 回车 选择Babel、Router、CSS Pre-processors、Linter / Formatter 回车 选择Use history mode for router? y 回车 选择Less 回车 选择ESLint with error prevention only 回车 选择Lint on save 回车 选择In dedicated config files 回车 选择Save this as a preset for future projects? N 回车 ...开始进行下载并且安装依赖 #启动axios-vue cd axios-vue npm run serve #安装axios依赖 npm install axios -S or yarn add axios #手动创建data.json(目录:public/data.json) { "title": "axios vue", "createTime": "2019-9" } #在home.vue中通过axios请求data.json,并且查看打印结果(src/view/home.vue) import axios from "axios"; created() { axios.get("/data.json").then(res => { console.log(res); }); }
2.2axios 请求方法及别名(get、post、put、patch、delete 方法)
  1. 2-2.vue
<template> <div class="home"></div> </template> <script> /* axios请求方法:get、post、put、patch、delete get:获取数据 post:提交数据(表单提交/文件上传) put:更新数据 (将所有的数据推送到后端) patch:更新数据 (只将修改的数据推送到后端) delete:删除数据 具体的提交方式是由后端来定义的 */ import axios from "axios"; export default { name: "axios-2", created() { //http://localhost:8080/data.json?id=1&name=%E5%BC%A0%E4%B8%89 //get请求第一种方式 axios .get("/data.json", { params: { id: 1, name: "张三" } }) .then(res => { console.log(res); }); //get请求第二种方式 axios({ method: "get", url: "/data.json", timeout: 1000, params: { id: 1, name: "张三" } }).then(res => { console.log(res); }); //post 存在两种数据格式的提交 //form-data 表单提交(图片上传、文件上传) //application/json //post请求第一种方式 let data = { id: 1 }; axios.post("/post", data).then(() => {}); //post请求第二种方式 axios({ method: "post", url: "/post", data: data }).then(() => {}); //form-data的post请求方式 let formData = new FormData(); for (let key in data) { formData.append(key, data[key]); } axios.post("/post", formData).then(() => {}); //那么put、patch也有两种方式类似于get、post,下面的演示咱们就只采取一种方式 axios.put("/put", data).then(() => {}); axios.patch("/patch", data).then(() => {}); //delete请求第一种方式 axios .delete("/delete", { params: { id: 1 } }) .then(() => {}); axios .delete("/delete", { data: { id: 1 } }) .then(() => {}); //delete请求第二种方式 axios({ method: "delete", url: "/delete", // params:{id:1}, data: { id: 1 } }); } }; </script>

2.在 router.js 当中增加 2-2.vue 的路由

{ path: '/axios-2', name: 'axios-2', component: () => import(/* webpackChunkName: "axios-2" */ './views/2-2.vue') }

3.创建一个 data.json (public/data.json)

{ "title": "axios vue", "createTime": "2019-9" }

4.那么请求地址就是:http://localhost:8080/axios-2

2.3 并发请求

1.2-3.vue 页面

<template> <div class="home"> <img alt="Vue logo" src="../assets/logo.png" /> </div> </template> <script> /* 并发请求: 同时进行多个请求,并统一处理返回值 */ import axios from "axios"; export default { name: "axios-2", created() { //axios.all、axios.spread axios.all([axios.get("/data.json"), axios.get("/city.json")]).then( axios.spread((dataRes, cityRes) => { console.log("dataRes", dataRes); console.log("cityRes", cityRes); }) ); } }; </script>

2.在 router.js 当中增加 2-3.vue 的路由

{ path: '/axios-3', name: 'axios-3', component: () => import(/* webpackChunkName: "axios-3" */ './views/2-3.vue') },

3.创建一个 data.json (public/city.json)

{ "name": "北京" }

4.那么请求地址就是:http://localhost:8080/axios-3

三、第 3 章 Axios 方法深入

3.1 创建 axios 实例

1.3-1.vue 页面

<template> <div class="home"></div> </template> <script> /* axios的实例 为什么我们要使用axios的实例呢? 因为在开发的过程中,我们可能会有不同的baseURL、timeout */ import axios from "axios"; export default { name: "axios3-1", created() { //axios的实例 let axios1 = axios.create({ baseURL: "http://localhost:8080", timeout: 1000 }); let axios2 = axios.create({ baseURL: "https://easy-mock.com/mock/5d5fb2ce9b58ad2249ff6c2b/mockapi", timeout: 5000 }); axios1.get("/data.json").then(res => { console.log(res); }); axios2.get("/table/high/list").then(res => { console.log(res); }); } }; </script>

2.在 router.js 当中增加 3-1.vue 的路由

{ path: '/axios3-1', name: 'axios3-1', component: () => import(/* webpackChunkName: "axios3-1" */ './views/3-1.vue') }

3.那么请求地址就是:http://localhost:8080/axios3-1

3.2 axios 基本的配置参数,以及在开发中的应用

1.3-2.vue 页面

<template> <div class="home"></div> </template> <script> import axios from "axios"; export default { name: "axios3-2", created() { //第一部分:axios基本的配置参数有哪些 axios.create({ baseURL: "http://localhost:8080", //请求域名,基本地址 timeout: 1000, //请求超时时长(ms) method: "get", //请求方式(post、put、patch、delete) url: "/data.json", //请求路径(接口) headers: { token: "" }, //请求头 params: {}, //请求参数拼接在url中 data: {} //请求参数放在请求体里面 }); //第二部分:axios三种参数配置方式以及优先级 //1.aixos的全局配置(优先级:低) axios.defaults.timeout = 1000; axios.defaults.baseURL = "http://localhost:8080"; //2.axios的实例配置(优先级:中) let instance = axios.create(); instance.defaults.timeout = 3000; //3.axios的请求配置(优先级:高) instance.get("/data.json", { timeout: 5000 }); //第三部分:axios实例在实际开发中的应用 //创建axios1实例 let axios1 = axios.create({ baseURL: "http://localhost:8080", timeout: 1000 }); //创建axios2实例 let axios2 = axios.create({ baseURL: "https://easy-mock.com/mock/5d5fb2ce9b58ad2249ff6c2b/mockapi", timeout: 3000 }); //在axios1实例中设计的参数有:baseURL、timeout:1000、method、params axios1 .get("/data.json", { params: { id: 1 } }) .then(res => { console.log(res); }); //在axios1实例中设计的参数有:baseURL、timeout:5000、method、params axios2 .get("/table/high/list", { timeout: 5000, params: { id: 1 } }) .then(res => { console.log(res); }); } }; </script>

2.在 router.js 当中增加 3-2.vue 的路由

{ path: '/axios3-2', name: 'axios3-2', component: () => import(/* webpackChunkName: "axios3-2" */ './views/3-2.vue') }

3.那么请求地址就是:http://localhost:8080/axios3-2

3.3 axios 拦截器

1.3-3.vue 页面

<template> <div class="home"></div> </template> <script> /* 拦截器:在请求或者响应被处理前拦截他们 let instance = axios.create() 请求拦截器 instance.interceptors.request.use(config=>return config,err=>return Promise.reject(err)) 响应拦截器 instance.interceptors.re.use(config=>return config,err=>return Promise.reject(err)) 取消拦截器 */ import axios from "axios"; import { Promise } from "q"; export default { name: "axios3-3", created() { let instance = axios.create({}); //请求拦截器 instance.interceptors.request.use( config => config, err => Promise.reject(err) ); //响应拦截器 instance.interceptors.response.use(res => res, err => Promise.reject(err)); //取消拦截器(了解) let interceptors = axios.interceptors.request.use(config => { config.headers = { auth: true }; return config; }); axios.interceptors.request.eject(interceptors); //例子 登录状态(token:'') 不需要登录的接口 let instance1 = axios.create({}); instance1.interceptors.request.use( config => { config.headers.token = ""; return config; }, err => { return Promise.reject(err); } ); //需要登录的接口 let instance2 = axios.create({}); instance2.get("/data.json"); //移动端开发的接口 let instance3 = axios.create({}); instance3.interceptors.request.use(config => { $("#modal").show(); //loading 显示 return config; }); instance3.interceptors.response.use( res => { $("#modal").hide(); //loading 隐藏 return res; }, err => { $("#modal").hide(); //loading 隐藏 return Promise.reject(err); } ); } }; </script>

2.在 router.js 当中增加 3-3.vue 的路由

{ path: '/axios3-3', name: 'axios3-3', component: () => import(/* webpackChunkName: "axios3-3" */ './views/3-3.vue') }

3.那么请求地址就是:http://localhost:8080/axios3-3

3.4 axios 错误处理

1.3-4.vue

<template> <div class="home"></div> </template> <script> /* 错误处理: 请求错误时进行的处理 */ import axios from "axios"; import { Promise } from "q"; import { Toast } from "vant"; export default { name: "axios3-4", created() { axios.interceptors.request.use( config => { return config; }, err => { return Promise.reject(err); } ); axios.interceptors.response.use( res => { return res; }, err => { return Promise.reject(err); } ); axios .get("/data.json") .then(res => { console.log(res); }) .catch(err => { console.log("err", err); }); //例子: 在实际开发过程中,一般添加统一的错误处理 let intance = axios.create({}); intance.interceptors.request.use( config => { return config; }, err => { //请求错误 一般http状态码以4开头,常见: 401超时,404 not found Toast.loading({ mask: false, message: "加载中..." }); return Promise.reject(err); } ); intance.interceptors.response.use( res => { return res; }, err => { //请求错误 一般http状态码以5开头,常见: 500系统错误,502系统重启 Toast.loading({ mask: false, message: "加载中..." }); return Promise.reject(err); } ); intance .get("/data1.json") .then(res => { console.log(res); }) .catch(err => { console.log(err); }); } }; </script>

2.在 router.js 当中增加 3-4.vue 的路由

{ path: '/axios3-4', name: 'axios3-4', component: () => import(/* webpackChunkName: "axios3-4" */ './views/3-4.vue') }

3.安装 vue 的一个 UI 组件库:vant 、babel-plugin-import

npm install vant -S npm install babel-plugin-import -D

4.配置 babel.config.js

module.exports = { presets: [ '@vue/app' ], plugins: [ ['import', { libraryName: 'vant', libraryDirectory: 'es', style: true }, 'vant'] ] }

5.那么请求地址就是:http://localhost:8080/axios3-4

3.5 axios 取消请求操作

1.3-5.vue 页面

<template> <div class="home"></div> </template> <script> /* 取消请求: 用于取消正在进行的http请求(了解) */ import axios from "axios"; export default { name: "axios3-5", created() { let source = axios.CancelToken.source(); axios .get("/data.json", { cancelToken: source.token }) .then(res => { console.log(res); }) .catch(err => { console.log(err); }); //取消请求操作(message 可选) source.cancel("cancel http"); //什么情况下可能用到取消请求 //在执行大量导出数据、或者查询数据的时候,请求时间过长3-5秒,这个过程我们可以进行取消请求的操作 } }; </script>

2.在 router.js 当中增加 3-5.vue 的路由

{ path: '/axios3-5', name: 'axios3-5', component: () => import(/* webpackChunkName: "axios3-5" */ './views/3-5.vue') }

3.那么请求地址就是:http://localhost:8080/axios3-5

四、第 4 章 Axios 实战

4.1 项目环境配置

1.安装 Vue 的一个 Ui 组件库:Vant(上面第 3 章咱们安装过了,这就不在重复赘述了)
2.启动一个 node 服务
下载 node 服务代码:https://github.com/web-gm/axios_node_api

cd axios_node_api npm install npm start

3.验证 node 服务是否请求成功:http://localhost:9000/api/contactList
看到数据则表示启动成功

4.2 项目实战联系人的(添加、编辑、删除)操作

1.新建 ContactList.vue 页面,引入需要的组件库,组件当中调用 UI 组件,模块中渲染组件,初始化组件数据,添加组件的事件等等操作

<template> <div class="home"> <van-contact-list :list="list" @add="onAdd" @edit="onEdit" /> <!-- 联系人编辑 --> <van-popup v-model="showEdit" position="bottom"> <van-contact-edit :contact-info="editingContact" :is-edit="isEdit" @save="onSave" @delete="onDelete" /> </van-popup> </div> </template> <script> import axios from "axios"; import { Popup, ContactList, ContactEdit, Toast } from "vant"; export default { name: "cantactList", components: { [Popup.name]: Popup, [ContactList.name]: ContactList, [ContactEdit.name]: ContactEdit }, data() { return { instance: null, editingContact: {}, showEdit: false, isEdit: false, list: [] }; }, created() { this.instance = axios.create({ baseURL: "http://localhost:9000/api", timeout: 5000 }); this.getContactList(); }, methods: { //联系人列表 getContactList() { this.instance .get("/contactList") .then(res => { console.log(res); if (res.data.code === 200) { this.list = res.data.data; } }) .catch(err => { console.log(err); Toast("请求失败,请稍后重试"); }); }, // 添加联系人 onAdd() { this.showEdit = true; this.isEdit = false; this.editingContact = {}; }, // 编辑联系人 onEdit(item) { this.isEdit = true; this.showEdit = true; this.editingContact = item; }, // 保存联系人 onSave(info) { if (this.isEdit) { //编辑操作 this.instance .put("/contact/edit", info) .then(res => { if (res.data.code === 200) { Toast("编辑成功"); this.getContactList(); } }) .catch(() => { Toast("请求失败,请稍后重试"); }); } else { //新建操作 this.instance .post("/contact/new/json", info) .then(res => { if (res.data.code === 200) { Toast("新建成功"); this.getContactList(); } }) .catch(() => { Toast("请求失败,请稍后重试"); }); } this.showEdit = false; }, // 删除联系人 onDelete(info) { this.instance .delete("/contact", { params: { id: info.id } }) .then(() => { Toast("删除成功"); this.getContactList(); }) .catch(() => { Toast("请求失败,请稍后重试"); }); this.showEdit = false; } } }; </script> <style scoped> .van-contact-list__add { z-index: 0; } .van-popup { height: 100%; } </style>

2.在 router.js 当中增加 ContactList.vue 的路由

{ path: '/contactList', name: 'contactList', component: () => import(/* webpackChunkName: "contactList" */ './views/ContactList.vue') }

3.那么请求地址就是:http://localhost:8080/contactList

4.3 axios 的封装

1.为什么要对 axios 进行封装呢?

  • 进行统一的容错处理
  • 进行公共入参的处理比如 headers
  • 对 api 接口地址进行统一管理
  • 如果接口请求时间过长,可以进行统一的正在加载中的处理

2.axios 封装分为哪几步骤呢?

1.API 接口地址的抽离
在 src 目录下创建一个 service/contactApi.js 的文件

const CONTACT_API = { //获取联系人列表 getContactList: { method: 'get', url: '/contactList' }, //新建联系人 form-data newContactForm: { method: 'post', url: '/contact/new/form' }, //新建联系人 application/json newContactJson: { method: 'post', url: '/contact/new/json' }, //编辑联系人 editContact: { method: 'put', url: '/contact/edit' }, //删除联系人 delContact: { method: 'delete', url: '/contact' } } export default CONTACT_API;

2.对 axios 的封装
在 src 目录下创建一个 service/http.js 的文件

import axios from 'axios'; import service from './contactApi'; import { Toast } from 'vant'; Toast.allowMultiple();//多了Toast并存 //service 循环遍历出不同的请求方法 let instance = axios.create({ baseURL: 'http://localhost:9000/api', timeout: 5000 }) const Http = {}; //包裹请求方法的容器 let globalLoadingStatus; //默认情况请求接口会出现”正在加载...“,如果入参idLoading:false,则就不会出现”正在加载“ //请求格式/参数的统一 for (let key in service) { let api = service[key]; //method,url //async 避免进入回调地狱 Http[key] = async function ( params,//请求参数 get、delete(url)、post、put、patch(data) isFormData = false,//是否是form-data的请求 config = {}, //配置参数 idLoading = true,//默认正在加载显示 ) { globalLoadingStatus = idLoading; let newParams = {}; //判断 content-type 是否是form-data if (params && isFormData) { newParams = new FormData(); for (let i in params) { newParams.append(i, params[i]) } } else { newParams = params } //不同请求的判断 let response = {}; if (api.method === 'post' || api.method === 'put' || api.method === 'patch') { try { response = await instance[api.method](api.url, newParams, config) } catch (err) { response = err } } else if (api.method === 'get' || api.method === 'delete') { config.params = newParams; try { response = await instance[api.method](api.url, config) } catch (err) { response = err } } return response } } //请求 拦截器 let toastLoading; instance.interceptors.request.use(config => { globalLoadingStatus = config.params ? (config.params.isLoading ? true : false) : globalLoadingStatus //发起请求前 if (globalLoadingStatus) { toastLoading = Toast.loading({ mask: false,//遮罩层 duration: 0,//一直存在 forbidClick: true,//禁止点击 message: '加载中...' }) } return config; }, err => { //请求错误 toastLoading && toastLoading.clear(); return Promise.reject(err) }) //响应 拦截器 instance.interceptors.response.use(res => { //请求成功了 toastLoading && toastLoading.clear(); if (res.data && res.status === 200) { return res.data } }, err => { // Toast('请求错误,请稍后重试'); toastLoading && toastLoading.clear(); return Promise.reject(err) }) export default Http;

3.新增页面 ContactList2.vue 页面

<template> <div class="home"> <van-contact-list :list="list" @add="onAdd" @edit="onEdit" /> <!-- 联系人编辑 --> <van-popup v-model="showEdit" position="bottom"> <van-contact-edit :contact-info="editingContact" :is-edit="isEdit" @save="onSave" @delete="onDelete" /> </van-popup> </div> </template> <script> import { Popup, ContactList, ContactEdit, Toast } from "vant"; export default { name: "cantactList", components: { [Popup.name]: Popup, [ContactList.name]: ContactList, [ContactEdit.name]: ContactEdit }, data() { return { instance: null, editingContact: {}, showEdit: false, isEdit: false, list: [] }; }, created() { this.getContactList(); }, methods: { //联系人列表 async getContactList() { let res = await this.$Http.contactList(); this.list = res.data; }, // 添加联系人 onAdd() { this.showEdit = true; this.isEdit = false; this.editingContact = {}; }, // 编辑联系人 onEdit(item) { this.isEdit = true; this.showEdit = true; this.editingContact = item; }, // 保存联系人 async onSave(info) { if (this.isEdit) { //编辑操作 let res = await this.$Http.editContact(info); if (res.code === 200) { Toast("编辑成功"); this.getContactList(); } } else { //新建操作 let res = await this.$Http.newContactJson(info); if (res.code === 200) { Toast("新建成功"); this.getContactList(); } } this.showEdit = false; }, // 删除联系人 async onDelete(info) { let res = await this.$Http.delContact({ id: info.id }); if (res.code === 200) { Toast("删除成功"); this.getContactList(); } this.showEdit = false; } } }; </script> <style scoped> .van-contact-list__add { z-index: 0; } .van-popup { height: 100%; } </style>

4.在 router.js 当中增加 ContactList2.vue 的路由

{ path: '/contactList2', name: 'contactList2', component: () => import(/* webpackChunkName: "contactList2" */ './views/ContactList2.vue') },

5.那么请求地址就是:http://localhost:8080/contactList2

五、第 5 章 Axios 总结

5.1 总结

针对 axios 封装要结合自己项目来进行封装,从而进行调整,这个案例只给了封装的一种思路,仅供在今后开发 axios 封装的参考。
1.axios 封装的一些扩展

  • 可以给请求添加统一的 loading (案例中已经给了一种方案)
  • 在 headers 添加 token 鉴权 (针对一些有需要登录接口或者后端需要传的一些 header 值)
  • 添加统一的错误处理,验证失败后一些页面跳转、清除一些验证数据等等

案例代码仓库地址: https://github.com/fx35792/axios-vue

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...