axios

125 阅读6分钟

juejin.im/post/684490…

一、axios的封装

在vue项目中,和后台交互获取数据这块,我们通常使用的是axios库,它是基于promise的http库,可运行在浏览器端和node.js中。它有很多优秀的特性,例如拦截请求和响应、取消请求、转换json、客户端防御XSRF等。

安装

npm install axios;  //安装axios

引入

//在http.js中引入axios

import axios from axios;//引入axios

import QS from ''qs";//引入qs模块,用来序列化post类型的数据,后面会提到

//vant的toast提示框组件,大家可以根据自己的ui组件更改

import {Toast} from 'vant';

环境的切换

我们的项目环境可能有开发环境、测试环境和生产环境。我们通过node的环境变量来匹配我们的默认的接口url前缀。axios.defaults.baseURL可以设置axios的默认请求地址就不多说了。

// 环境的切换  开发环境  测试环境和生产环境if(process.env.NODE_ENV=='development'){    axios.defaults.baseURL='https://www.baidu.com';}else if(process.env.NODE_ENV=='debug'){    axios.defaults.baseURL='https://www.ceshi.com'}else if(process.env.NODE_ENV=='production'){    axios.defaults.baseURL='https://www.production.com'}

设置请求超时

通过axios.defaults.timeout设置默认的请求超时时间。例如超过了10s,就会告知欧用户当前请求超时,请刷新等。

axios.defaults.timeout=10000;

post请求头的设置

post请求的时候,我们需要加上一个请求头,所以可以在这里进行一个默认的设置,即设置post的请求头为application/x-www-form-urlencoded;charset=UTF-8

axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;charset=UTF-8';

********

请求拦截

我们在发送请求前可以进行一个请求的拦截,为什么要拦截呢,我们拦截请求是用来做什么的呢?比如,有些请求是需要用户登录之后才能访问的,或者post请求的时候,我们需要序列化我们提交的数据。这时候,我们可以在请求被发送之前进行一个拦截,从而进行我们想要的操作。

// 请求拦截器axios.interceptors.request.use(    config=>{        // 每次发送请求之前判断vuex中是否存在token        // 如果存在,则统一在http请求的header都加上token,这样后台根据token判断你的登录情况        // 即使本地存在token,也有可能token是过期的,所以在响应拦截器中要对返回来状态进行判断        const token=store.state.token;        token&&(config.headers.Authorization=token);        return config;    },    error=>{        return Promise.error(error)    })

这里说一下token,一般是在登录完成之后,将用户的token通过localStorage或者cookie存在本地,然后用户每次进入页面的时候(即在main.js中),会首先从本地存储中读取token,如果token存在说明用户已经登陆过,则更新vuex的token状态。然后在每次请求接口的时候,都会在请求的header中携带token,后台人员就可以根据你携带的token来判断你的登录是否过期,如果没有携带,则说明没有登录过。这时候或许有些小伙伴会有疑问了,就是每个请求都携带token,那么要是一个页面不需要用户登录就可以访问的怎么办呢?其实,你前端的请求可以携带token,但是后台可以选择不接收啊!

// 响应的拦截axios.interceptors.response.use(    response=>{        // 如果返回的状态码为200,说明接口请求成功,可以正常拿到数据        // 否则的话抛出错误        if(response.status===200){            return Promise.resolve(response);        }else{            return Promise.reject(response);        }    },    // 服务器状态码不是2开头的情况    // 这里可以跟你们的后台开发人员协商统一的错误状态码    // 然后根据返回的状态码进行一些操作,例如登录过期提示,错误提示等等    // 下面列举几个常见的操作,其他需求可自行扩展    error=>{        if(error.response.status){            switch(error.response.status){                // 401:未登录                // 未登录跳转页面,并携带当前页面的路径                // 在登录成功后返回当前页面,这一步需要在登录页操作                case 401:                    router.replace({                        path:'/login',                        query:{                            redirect:router.currentRoute.fullPath                        }                    })                    break;                // 403 token过期                // 登录过期用户进行提示                // 请出本地token和情况vuex中的token对象                // 跳转到登录页面                case 403:                    Toast({                        message:'登录过期,请重新登录',                        duration:1000,                        forbidClick:true                    })                    // 清除缓存                    localStorage.removeItem('token');                    store.commit('loginSuccess',null);                    // 跳转到登录页面,并将要浏览的页面fullPath传过去,登录成功后跳转需要访问的页面                    setTimeout(()=>{                        router.replace({                            path:'/login',                            query:{                                redirect:router.currentRoute.fullPath                            }                        })                    },1000);                    break;                // 404 请求不存在                case 404:                    Toast({                        message:'网络请求不存在',                        duration:1500,                        forbidClick:true                    })                    break;                // 其他错误,直接抛出错误提示                default:                    Toast({                        message:error.response.data.message,                        duration:1500,                        forbidClick:true                    })            }            return Promise.reject(error.response);
        }    })

响应拦截很好理解,就是服务器返回给我们的数据,我们在拿到之前可以对他进行一些处理。例如上面的思想:如果后台返回的状态码是200,则正常返回数据,否则的根据错误的状态码类型进行一些我们需要的错误,其实这里主要就是进行了错误的统一处理和没登录或登录过期后调整登录页的一个操作。

要注意的是,上面的Toast()方法,是我引入的vant库中Toast轻提示组件,你根据你的UI库,对应使用你的一个提示组件。

二、get和post

/** * get方法,对应get请求 * @param {String} url [请求的url地址] * @param {Object} params [请求时携带的参数] */export function get(url,params){    return new Promise((resolve,reject)=>{        axios.get(url,{            params:params        }).then(res=>{            resolve(res.data)        }).catch(err=>{            reject(err.data)        })    })}

post方法:原理同get基本一样,但是要注意的是,post方法必须要使用对提交从参数对象进行序列化的操作,所以这里我们通过node的qs模块来序列化我们的参数。这个很重要,如果没有序列化操作,后台是拿不到你提交的数据。这就是文章开头我们import QS from 'qs';的原因。

/** * post方法  对应post请求 * @params {String} url [请求的url地址] * @param {Object}  params [请求时携带的参数] */
 export function post(url,params){     return new Promise((resolve,reject)=>{         axios.post(url,QS.stringify(params)).then(res=>{             resolve(res.data)         }).catch(err=>{             reject(err.data)         })     }) }

三、api接口统一管理

1. 首先我们在api.js中引入我们封装的get和post方法

import {get,post} from './http'

现在,例如我们有这样一个接口,是一个post请求

www.baiodu.com/api/v1/user…

我们可以在api.js中这样封装:

export const apiAddress=p=>post('api/v1/users/my_address/address_edit_before',p)

然后在我们的页面中可以这样调用我们的api接口

import { apiAddress } from '@/request/api';// 导入我们的api接口
export default {        
    name: 'Address',    
    created () {
        this.onLoad();
    },
    methods: {            
        // 获取数据            
        onLoad() {
            // 调用api接口,并且提供了两个参数                
            apiAddress({                    
                type: 0,                    
                sort: 1                
            }).then(res => {
                // 获取数据成功后的其他操作
                ………………                
            })            
        }        
    }
}