一、第 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 方法)
- 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 值)
- 添加统一的错误处理,验证失败后一些页面跳转、清除一些验证数据等等
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于