Vue中网络请求方面的思考(Token、axios封装和拦截)

4/13/2023

# 什么是token?

所谓的Token,其实就是服务端生成的一串加密字符串、以作客户端进行请求的一个“令牌”。当用户第一次使用账号密码成功进行登录后,服务器便生成一个Token及Token失效时间并将此返回给客户端,若成功登陆,以后客户端只需在有效时间内带上这个Token前来请求数据即可,无需再次带上用户名和密码。

通常前端拿到后台返回的token后会存储到浏览器缓存当中,在每次发起网络请求都将它添加到请求头headers的Authorization字段里。
存储:

  1. 存储在localStorage或sessionStorage 中,每次调用接口的时候都把它当成一个字段传给后台;
  2. 存储在cookie 中,让它自动发送,不过缺点就是不能跨域; ( 注: js-cookie插件 )

接下来就是将token添加到HTTP请求头headers中...

# 什么是Axios?

Axios 是一个基于 Promise 的轻量级HTTP 库, 可以用在浏览器和 node.js 中, 用于发起网络请求;
前端项目中使用Axios时, 通常会对Axios做一些封装, 比如在网络请求前和响应前做些什么, 能在一定程度上减小代码冗余和后期维护;

# Vue中axios请求封装

axios基础配置 :

//request.js
import axios from "axios"
import router from "@/router";
//创建axios实例
let axiosInstance = axios.create({
    baseURL:"/",
    timeOut:1000*12
})
//添加post请求媒体类型
axiosInstance.defaults.headers.post['Content-Type'] = 'application/json';

请求拦截和响应拦截 :

//请求拦截
axiosInstance.interceptors.request.use(
    (config)=>{
        //假设登录成功时token存在localStorage中
        const token = localStorage.getItem("myToken")
        token && (config.headers.Authorization = token)
        return config
    },
    (err)=>{
        return Promise.reject(err)    
    }
)
//响应拦截
axiosInstance.interceptors.response.use(
    (response)=>{
        // 2xx 范围内的状态码都会触发该函数。
        //可通过与后台约定的code字段做相应的提示(例:接口状态码200,返回数据的code字段为401主动跳转登录页)
        if(response.data.code === 200){
            return response
        }else if(response.data.code === 401){
            //提示用户'登录过期,请重新登录',跳转登录页
            router.replace({
                path:"/login"            
            })        
        }else if(response.data.code === 403){
            //提示用户没有权限      
        }else if(response.data.code === 404){
            //提示网络请求不存在      
        }
        //...
        
    },
    (err)=>{
        /* 超出 2xx 范围的状态码都会触发该函数(例:如果登录过期,但接口的状态码不是200,是401时,可以在此处
           通过判断err.response.status === 401来提示登录过期,具体在response还是err里提示可与后台约定*/)
        }
        return Promise.reject(error);  
    }
)

一、暴露axios实例,请求数据 :

//request.js
export default axiosInstance
//统一接口文件server.js
import axiosInstance from "./request.js"
export function DownloadInfoList(params=>{
    return axiosInstance({
        url:"/info/download/list",
        method:"get",
        params,//指定使用params传参
        responseType:"blob"    
    })
})  
/*在axios中,使用params字段传递的参数会拼接在url上,使用data字段传递的参数会放在请求体body中,即
get请求方式使用params字段传参,post请求使用data字段传参*/  

二、上一步也可以不暴露axios实例,用axios实例axiosInstance进一步封装常用的get、post、put、delete请求 :

//get请求
export function Get(url,params,config){
    return new Promise((resolve,reject)=>{
        axiosInstance.get(url,{ params,...config })
        .then(res=>{
            resolve(res.data)        
        })
        .catch(err=>{
            reject(err)  
        })     
    })
}
//post请求
export function Post(url,params,config){
    return new Promise((resolve)=>{
        axiosInstance.post(url,params,config)
        .then(res=>{
            resolve(res.data)        
        })
        .catch(err=>{
            reject(err)       
        })     
    })
}
//put请求
export function Put(url,params,config){
    return new Promise((resolve)=>{
        axiosInstance.put(url,params,config)
        .then(res=>{
            resolve(res.data)        
        })
        .catch(err=>{
            reject(err)       
        })     
    })
}
//delete请求(params和data传参都支持)
export function Get(url,params,config){
    return new Promise((resolve,reject)=>{
        axiosInstance.get(url,{ params:{...params},...config }) //可以这样指定使用params传参
        .then(res=>{
            resolve(res.data)        
        })
        .catch(err=>{
            reject(err)  
        })     
    })
}

使用封装好的Get、Post、Put、Delete请求:

//统一接口文件server.js
import { Get、Post、Put、Delete } from "./request.js"
const DownloadInfoList = (p)=> Get("info/download/list",p,{responseType:"blob"})
//组件内使用
DownloadInfoList({name:"123"}).then(res=>{
    //do something
}).catch(err=>{
    //do something
})