axios的二次封装:

3,213 阅读7分钟

前言:

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;