前言:
axios的封装根据需求的不同而不同,最近也根据自己的项目需求,对axios和api进行了封装,其实封装的目的为了帮助我们简化代码更利于 后期的更新维护。
那么想了解axios的封装,你是否对axios是什么,怎么来的,他有什么作用,什么场景使用和特点是否感到疑惑呢?其实我也有点疑惑,下面是个人的一些学习经历,希望各位同僚多多指正。
axios概念了解:
axios是什么:
Axios 是一个基于 promise 的 HTTP 库,可以用在浏览器和 node.js 中。
简单的讲就是可以发送get、post请求。说到get、post,大家应该第一时间想到的就是Jquery吧,毕竟前几年Jquery比较火的时候,大家都在用他。但是由于Vue、React等框架的出现,Jquery也不是那么吃香了。也正是Vue、React等框架的出现,促使了Axios轻量级库的出现,因为Vue等,不需要操作Dom,所以不需要引入Jquery.js了。
axios特性:
从浏览器中创建 XMLHttpRequests
从 node.js 创建 http 请求
支持 Promise API
拦截请求和响应
转换请求数据和响应数据
取消请求
自动转换 JSON 数据
客户端支持防御 XSRF
axios的应用场景:
axios主要是用于向后台发起请求的,还有在请求中做更多是可控功能。 在特性里面已经有提到,浏览器发送请求,或者Node.js发送请求都可以用到Axios。像Vue、React、Node等项目就可以使用Axios。
promise是什么:
是一个对象用来传递异步操作的信息,它代表了某个未来才会知道结果的事件(通常是一个异步操作),并且这个事件提供统一的api,可供进一步的处理。解决了臭名昭著的‘回掉地狱’。 进一步了解:promise学习
Axios的封装使用:
安装模块:
```
npm install axios
```
或者直接引入CDN
```
```
引入
//自己定义的类AjaxRequest.js 这个文件也是我用来封装axios的文件
import axios from "axios" // 封装一个比较好用的axios
class AjaxRequest{
constructor(){
// 请求的基础路径
this.baseURL = process.env.NODE_ENV == "production" ? "/" : "http://localhost:3030"
// 超时时间
this.timeout = 3000;
}
//调用api传过来的options和construcoroptions的合并
//api 例如 request("/user","post","name=z3")
merge(options){
return {...options,baseURL:this.baseURL,timeout:this.timeout}
}
//请求方法
request(options){
let instance = axios.create();
let config = this.merge(options);
return instance(config)
}
}
export default new AjaxRequest;
设置环境:
项目部署环境一般可以分为三种:生产环境,测试环境,开发环境。
-
开发环境:开发环境时程序员专门用于开发的服务器,配置可以比较随意,为了开发调试方便,一般打开全部错误报告和测试工具,是最基础的环境。 开发环境的分支,一般是feature分支。
-
测试环境:一般是克隆一份生产环境的配置,一个程序在测试环境工作不正常,那么肯定不能把它发布到生产服务器,是开发环境到生产环境的过度环境。 测试环境的分支存在bug,一般不会让用户和其他人看到,并且测试环境会尽量与生产环境相似。
-
生产环境:生产环境是指正式提供对外服务的,一般会关掉错误报告,打开错误日志,是最重要的环境。部署分支一般为master分支。
三个环境也可以说是系统开发的三个阶段:开发=》测试=》上线,其中生产环境也就是通常说的真实的环境,最后交给用户的环境。
我们通过node的环境变量来匹配我们的默认的接口url前缀。
//这里当作生产环境了
this.baseURL = process.env.NODE_ENV == "production" ? "/" : "http://localhost:3030"
设置超时:
加入请求中,超过了3s将会告知客户端,请求超时,请刷新。
this.timeout = 3000;//访问接口时间 超时了 3s
封装axios.request
这个方法,是为了我在api调用接口文档时候,直接调用的。
request(options){
//创建一个axios实例
let instance = axios.create();
let config = this.merge(options);
return instance(config)
}
引入store仓库
这里需要用到store中的状态信息 引入store vuex
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
isShowLoading:true,
username:"wangcai"
},
mutations: {
//小圆圈 显示 和消失 属于状态 封装到store中
showLoading(state){
state.isShowLoading = true;
},
hideLoading(state){
state.isShowLoading = false;
}
},
actions: {
}
})
请求拦截
在请求或响应被 then 或 catch 处理前拦截它们。
我们在发送请求前可以进行一个请求的拦截,对请求数据进行加工,比如:加入一个加载动画,加入一些需要的头部header,下面也简单实现了一把
模板:
// 添加请求拦截器
axios.interceptors.request.use(function (config) {
// 在发送请求之前做些什么
return config;
}, function (error) {
// 对请求错误做些什么
return Promise.reject(error);
});
实例化:
setInterceptor(instance,url){
// 每次请求时,都要加上一个loading效果
instance.interceptors.request.use((config)=>{
config.headers.Authorization = "xxx"; //做jwt需要用到这个头 在请求的时候 拦截下来 加上这个头
// 第1次请求时,显示Loading动画
if(Object.keys(this.queue).length === 0){
store.commit('showLoading'); //只让小动画 显示一次 后来在一直请求 就不用一直转转
}
this.queue[url] = url;
return config;
});
}
响应拦截:
响应拦截器很好理解,就是服务器返回给我们的数据,我们在拿到之前可以对他进行一些处理。比如这个时候我们同样可以在数据回来之前加一个动画加载,并且对我们的数据过滤。
// 添加响应拦截器
axios.interceptors.response.use(function (response) {
// 对响应数据做点什么
return response;
}, function (error) {
// 对响应错误做点什么
return Promise.reject(error);
});
instance.interceptors.response.use((res)=>{
delete this.queue[url]
if(Object.keys(this.queue).length === 0){
store.commit('hideLoading')
}
// store.commit('hideLoading')
return res.data; //相应拦截 过滤数据
});
针对上面提到的jwt使用后面还会说到:JWT学习
api的封装使用:
封装api接口:
// 用户相关的接口
import axios from "../libs/ajaxRequest" //自己封装的ajax
//向外暴露一个方法 谁调用这个方法 相当于 返回一个ajax的实例
export const getUser = ()=>{
return axios.request({
url:'/user',
method:'get'
})
}
调用api接口:
import {getUser} from "../api/user";
export default {
name: 'home',
components: {
},
async mounted(){
//将调用接口
let a = await getUser()
console.log(a);
}
}
</script>
server.js本地服务
本地创建一台服务:
let express = require("express")
let bodyParser = require("body-parser")
let app = express()
// 配置跨域
app.use((req,res,next)=>{
res.header("Access-Control-Allow-Origin","*");
res.header("Access-Control-Allow-Methods","GET,HEAD,OPTIONS,POST,PUT"),
res.header("Access-Control-Allow-Headers","Origin,X-Requested-With,Content-Type,Accept,Authorization")
if(req.method.toLowerCase() === "options"){
return res.end();
}
next();
})
// 配置bodyparser
app.use(bodyParser.json())
app.get("/user",(req,res)=>{
setTimeout(()=>{
res.json({name:"wangcai"})
},500)
})
app.listen(3030)
api接口管理的一个好处就是,我们把api统一集中起来,如果后期需要修改接口,我们就直接在api.js中找到对应的修改就好了,而不用去每一个页面查找我们的接口然后再修改会很麻烦。关键是,万一修改的量比较大,就规格gg了。还有就是如果直接在我们的业务代码修改接口,一不小心还容易动到我们的业务代码造成不必要的麻烦。
axios源码:
import axios from "axios" //封装一个比较好用的 ajax
import store from "../store"
// 当第一次请求时,显示loading 线上 开发环境 生产环境区别 process 一个进程
class AjaxRequest{
constructor(){
//当我调用接口是 这个http://localhost就不用重复写了额
this.baseURL = process.env.NODE_ENV == "production" ? "/" : "http://localhost:3030"
this.timeout = 3000;//访问接口时间 超时了 3s
this.queue = {}; // 存放每一次的请求
/**
* 我按钮 一直点 10次 请求的url一样 这个多次请求 我只需要 看你第一个请求
*/
}
//目的把baseURL 和 timeout 和 /user混合一块 合并
merge(options){
return {...options,baseURL:this.baseURL,timeout:this.timeout}
}
setInterceptor(instance,url){
// 每次请求时,都要加上一个loading效果
instance.interceptors.request.use((config)=>{
config.headers.Authorization = "xxx"; //做jwt需要用到这个头 在请求的时候 拦截下来 加上这个头
// console.log(this.queue) // {}
// console.log(Object.keys(this.queue)) // []
// 第1次请求时,显示Loading动画
if(Object.keys(this.queue).length === 0){
store.commit('showLoading'); //只让小动画 显示一次 后来在一直请求 就不用一直转转
}
this.queue[url] = url;
return config;
});
instance.interceptors.response.use((res)=>{
delete this.queue[url]
if(Object.keys(this.queue).length === 0){
store.commit('hideLoading')
}
// store.commit('hideLoading')
return res.data; //相应拦截 过滤数据
});
}
request(options){
let instance = axios.create(); //创建一个ajax实例 发出请求
this.setInterceptor(instance,options.url); // 设置拦截
let config = this.merge(options);
return instance(config) //实例 表示调用ajax 返回一个ajax的实例
}
}
export default new AjaxRequest;