Axios packaging and API interface management in the vue project

One, axios package

In the vue project, we usually use the axios library to interact with the background to obtain data, which is a promise-based http library that can run on the browser side and node.js. It has many excellent features, such as intercepting requests and responses, canceling requests, converting json, and defending against XSRF on the client side. Therefore, our Yuda also decisively gave up the maintenance of its official library vue-resource, and directly recommended us to use the axios library. If you still don’t know about axios, you can move to the axios document.

installation:

npm install axios; // 安装axios复制代码

Introduction:
Generally, I will create a request folder in the src directory of the project, and then create a http.js and an api.js file in it. The http.js file is used to encapsulate our axios, and api.js is used to manage our interface uniformly.

// 在http.js中引入axios
import axios from 'axios'; // 引入axios
import QS from 'qs'; // 引入qs模块,用来序列化post类型的数据,后面会提到
// vant的toast提示框组件,大家可根据自己的ui组件更改。
import {
    
     Toast } from 'vant'; 
复制代码

Environment switching:
Our project environment may include development environment, test environment and production environment. We use node's environment variables to match our default interface url prefix. Axios.defaults.baseURL can set the default request address of axios, not much to say.

// 环境的切换
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';
}复制代码

Set request timeout
Set the default request timeout time through axios.defaults.timeout. For example, if it exceeds 10s, the user will be notified that the current request has timed out, please refresh, etc.

axios.defaults.timeout = 10000;复制代码

When setting the post request header
, we need to add a request header, so we can make a default setting here, that is, set the request header of the post toapplication/x-www-form-urlencoded;charset=UTF-8

axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;charset=UTF-8';复制代码
  • Request interception
    We can intercept a request before sending the request. Why do we intercept it, and what do we intercept the request for? For example, some requests need to be accessed after the user logs in, or when post requests, we need to serialize the data we submit. At this time, we can perform an interception before the request is sent to perform the operation we want.
// 先导入vuex,因为我们要使用到里面的状态对象
// vuex的路径根据自己的路径去写
import store from '@/store/index';

// 请求拦截器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);    
})
复制代码

Let me talk about the token here. Generally, after the login is completed, the user's token is stored locally through localStorage or cookie, and then every time the user enters the page (that is, in main.js), the token is first read from the local storage. , If the token exists, indicating that the user has logged in, update the token status in vuex. Then, every time the interface is requested, the token will be carried in the header of the request, and the background staff can judge whether your login has expired based on the token you carry. If you do not carry it, it means you have not logged in. At this time, some friends may have questions, that is, every request carries a token. What if a page can be accessed without the user's login? In fact, your front-end request can carry token, but the back-end can choose not to receive it!

  • Response interception
// 响应拦截器
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
                    });
                    // 清除token
                    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);
        }
    }    
});复制代码

The response interceptor is well understood, that is, the data that the server returns to us, we can do some processing on it before we get it. For example, the above thought: If the status code returned by the background is 200, then the data will be returned normally, otherwise we will make some errors we need according to the wrong status code type. In fact, the main reason here is to perform unified processing of errors and not log in or log in expired. After adjusting an operation of the login page.

It should be noted that the Toast() method above is the toast light prompt component in the vant library that I introduced. You can use one of your prompt components according to your ui library.

Encapsulation of get method and post method
Our commonly used ajax request methods include get, post, put and other methods, I believe that the little friends will not be unfamiliar. There are many similar methods for axios. If you are unclear, you can read the document. But in order to simplify our code, we still have to carry out a simple package. Below we mainly encapsulate two methods: get and post.

The get method : We define a get function. The get function has two parameters. The first parameter represents the URL address we want to request, and the second parameter is the request parameter we want to carry. The get function returns a promise object. When the axios request succeeds, the resolve server returns the value, and when the request fails, it rejects the error value. Finally, the get function is thrown through export.

/**
 * 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 method : The principle is basically the same as that of get, but it should be noted that the post method must use the operation of serializing the submitted parameter object, so here we use the qs module of node to serialize our parameters. This is very important. If there is no serialization operation, the data you submit will not be available in the background. This is why we import QS from'qs'; at the beginning of the article. If you don’t understand what serialization means, just Baidu, there are a lot of answers.

/** 
 * post方法,对应post请求 
 * @param {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)
        })
    });
}复制代码

Here is a small detail, there is still a difference between the axios.get()method and axios.post()the way the parameters are written when submitting the data. The difference is that the second parameter of get is a {}, and then the params attribute value of this object is a parameter object. The second parameter of post is a parameter object. Pay attention to the slight difference between the two!

The encapsulation of axios is basically completed, let's briefly talk about the unified management of api.

The neat api is like a circuit board, and the entire circuit can be clear even if it is complicated. As mentioned above, we will create a new api.js, and then store all our api interfaces in this file.

  • First, we introduce our encapsulated get and post methods in api.js
/**   
 * api接口统一管理
 */
import {
    
     get, post } from './http'复制代码

Now, for example, we have such an interface, which is a post request:

http://www.baiodu.com/api/v1/users/my_address/address_edit_before复制代码

We can encapsulate in api.js like this:

export const apiAddress = p => post('api/v1/users/my_address/address_edit_before', p);复制代码

We define a apiAddressmethod, this method has a parameter p, p is the parameter object carried when we request the interface. Then we called the encapsulated postmethod. postThe first parameter of the method is our interface address, and the second parameter is apiAddressthe p parameter, which is the parameter object carried when requesting the interface. Finally export through exportapiAddress。

Then we can call our api interface in our page like this:

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

For other api interfaces, just continue to expand below in pai.js. Friendly reminder, write a note for each interface! ! !

One of the benefits of api interface management is that we centralize the api. If the interface needs to be modified later, we can directly find the corresponding modification in api.js, instead of going to every page to find our interface and then modify it. It will be troublesome. The key is, in case the amount of modification is relatively large, the specification is gg. Also, if you modify the interface directly in our business code, it is easy to move our business code and cause unnecessary trouble if you are not careful.

Ok, finally the completed axios package code is presented.

/**axios封装
 * 请求拦截、相应拦截、错误统一处理
 */
import axios from 'axios';import QS from 'qs';
import {
    
     Toast } from 'vant';
import store from '../store/index'

// 环境的切换
if (process.env.NODE_ENV == 'development') {
    
        
    axios.defaults.baseURL = '/api';
} else if (process.env.NODE_ENV == 'debug') {
    
        
    axios.defaults.baseURL = '';
} else if (process.env.NODE_ENV == 'production') {
    
        
    axios.defaults.baseURL = 'http://api.123dailu.com/';
}

// 请求超时时间
axios.defaults.timeout = 10000;

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

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

// 响应拦截器
axios.interceptors.response.use(    
    response => {
    
            
        if (response.status === 200) {
    
                
            return Promise.resolve(response);        
        } else {
    
                
            return Promise.reject(response);        
        }    
    },
    // 服务器状态码不是200的情况    
    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                    
                    });                    
                    // 清除token                    
                    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);        
        }       
    }
);
/** 
 * 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方法,对应post请求 
 * @param {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)        
        })    
    });
}
复制代码

Guess you like

Origin blog.csdn.net/qq_45846359/article/details/112574006