边摸边学 vue拦截器与api统一管理记录

1,934 阅读5分钟

本以为对vue使用的了解已经可以了(仅仅是使用),但是没想到还是太嫩了,经过看各位大佬的笔记和视频,终于有点头绪了,记录下我的实现的过程,这是以我自己开展的解题思路而进行的步骤。

一、安装axios

axios是我在vue中使用最多的请求工具,没有之一,对他也是情有独钟,这里给出他的网站,想了解详细的,请进www.axios-js.com/docs/vue-ax…

以及npm中查看axios,请进www.npmjs.com/package/axi…

npm install axios


二、创建请求拦截与api管理文件夹及路径呈现


如上图,这是在一个uni-app的框架中,在src文件夹下,创建request文件夹,里面基础包含的文件大致如图。request是我们这个vue拦截器与api管理的整个文件夹,里面分为两部分,其一为http.js文件,里面用于封装axios;其二是api文件夹,里面有三部分组成,index.js是作为api统一管理的出口文件;base.js是为了便于多人开发,实现更深模块化层级;images.js是在多种业务api模块的一个(如文章模块,用户模块等)可以有多个。刚开始看不太懂没事,先有个印象,可以更好的理解。下面进入我们正题。

三、引入axios及其他插件

在src文件夹下创建request文件夹,下面创建一个http.js文件和api文件夹,首先进入http.js中,引入代码:

import axios from 'axios'
//引入vuex 地址因项目而异
import store from '@/store/index.js'
// import { Toast } from 'vant'

这里可以引入ui插件,利于美化,如vant的弹出框Toast,并将其封装下:

// 提示函数 
const tip = (msg) => {
    Toast({
        message: msg, // 弹窗内容        
        duration: 1000, // 显示一秒关闭        
        forbidClick: true // 禁止点击蒙层    
    })  
}


四、创建axios实例对象及请求头配置

创建axios实例对象

var instance = axios.create({
    timeout : 1000 * 10  //设置请求超时时间
})

// 设置post请求头配置
instance.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;charset=UTF-8';


五、请求拦截

请求拦截器:顾名思义,在每次发送请求之前,拦截请求数据;

在此处,我们需要判断vuex中是否存在token,(一般可以使用 localStorage, sessionStorage 或者 cookie来保存)存在则在请求header加上token 后台根据token判断登录情况,即使本地有token 也可能token是过期的,是所以在响应拦截器中要对返回值进行判断,在http.js中,代码如下:

//请求拦截器
instance.interceptors.request.use(config => {
    const token = store.state.token    
    token && (config.headers.Authorization = token) // 此处的Authorization 根据后台人员提供
    return config},
    error => {
        return Promise.error(error)    
})

六、响应拦截

响应拦截器:发送请求后,当服务器返回响应数据时,拦截数据;

响应拦截的判断较多些,有未登录,401, 403, 404, 断网等情况;(401,403,这些错误返回是根据后台人员设定);在错误的情况下,会带着当前页面的fullPath到登录页面重新登录,成功后则跳回当前页面;

在http.js中,代码如下:

//响应拦截器
instance.interceptors.response.use(response => {
    // 如果返回的状态码为200 说明接口请求成功
     //否则错误
    if (response.status === 200) {
        return Promise.resolve(response)    
} else {
        return Promise.reject(response)
    }},    
// 根据后台返回的状态码 进行操作 如登录过去,错误提示    
// 例如下面几个    
error => {
        if (error.response) {
            switch (error.response.status) {
                // 未登录
                // 未登录则跳转登录页面 携带当前页面的路径 
               // 在登录成功后返回当前页面,在登录页面操作
                case 401:
                    // 可封装成 login()
                    router.replace({
                        path: '/login',
                        query: {
                            redirect: router.currentRoute.fullPath
                        }
                    })
                    break;
                // 403 token过期
                // 登录过期对用户进行提示
                // 清除本地token和vuex中token对象
                //跳转登录页面
                case 403:
                    tip('登录过期,请重新登录')
                    // Toast({
                    //     message: "登录过期,请重新登录",
                    //     duration: 1000,
                    //     forbidClick: true
                    // })
                    // 清除token
                    localStorage.removeItem('token')
                    store.commit('loginSuccess', null)
                    //跳转登录页面 并将浏览的页面fullpath传过去,登录成功后跳转需要访问的页面
                    setTimeout(() => {
                        router.replace({
                           path: '/login',
                            query: {
                                redirect: router.currentRoute.fullPath
                            }
                        })
                    }, 1000);
                    break;
                // 404 请求不存在
                case 404:
                    tip('网络请求不存在')
                    // Toast({
                    //     message: '网络请求不存在',
                    //     duration: 1000,
                    //     forbidClick: true
                    // })
                    break;
                // 其他错误
                default:
                    tip( error.response.data.message)
                    // Toast({
                    //     message:,
                    //     duration: 1500,
                    //     forbidClick: true
                    // })
            }
            return Promise.reject(error)
        }else{
            // 处理断网的情况
            // 请求超时 或者断网的情况 更新state的network状态
            // network 状态在app.vue 中控制全局的断网提示组件的显示隐藏 
           if (!window.navigator.onLine) {
                store.commit('changeNetWork', false)
            }else{
                return Promise.reject(error)
              }
        }
    })

最后抛出整个axios实例

export default instance


七、创建api统一管理模块

在api文件夹下,创建index.js,base.js,images.js(此文件名可自拟),index.js的作用便是用于api的统一管理出口,将项目全部的api集体引入,并抛出,利于多人开发,每个人制作一个模块;index.js代码例子如下:

//用于统一管理api接口 api统一出口 创建api index.js为了更加模块化 不同的业务api按模块分类 更好管理
// 引入图片模块的api 
import images from './images'
//其他模块文件

export default{
    images
    //... 其他
}


base.js文件的作用是多人开发中或者多个域名接口,便于统一修改,管理,代码如下:

// 接口域名管理 方便多人开发 多个接口
const base  = {
    kp: 'https://api.apiopen.top',
    kk: 'http://xxxxx22222.com/api'}export default base
}


最后一个业务模块中的一个图片模块 images.js,管理该模块下的api,为了不同业务的api进行分类,模块化,代码如下:(QS是用于post提交的数据进行序列化处理)

//引入域名管理 axios实例 和QS
import base from './base'
import axios from '../http'
import QS from 'qs'//获取图片列表
const images = {
   // 图片列表
    apiGetImages(data){
        return axios.get(base.kp + '/getImages')
    },
   // post请求
    login(params){
        return axios.post(base.kk + '/getName',qs.stringify(params))
    }}

export default images


八、全局引入api

为了方便在各个页面调用api请求

// 为了方便api的调用 将其引入全局中
import api from './request/api'
// 将api挂载在全局中
Vue.prototype.$api = api 


九、页面调用

created() {
        this.$api.images.apiGetImages(null).then(res => {
            console.log(res.data)
        }).catch(err =>{
            console.log(err)
        })
    }



以上便是我大致的过程。

此文的爸爸是 juejin.cn/post/684490…

前端小白,发布笔记,欢迎点赞鼓励,若发现文中有错误遗漏,望不吝赐教。