axios interception, api unified management

brief introduction

The encapsulation of axios and the unified management of api interface are actually designed to help us simplify the code and facilitate the later update and maintenance.

In the vue project, we usually use the axios library to interact with the background to obtain data. It is an http Library Based on promise, which can run on the browser and node JS. It has many excellent features, such as intercepting requests and responses, canceling requests, transforming json, client defense XSRF, etc. Therefore, our Youda also resolutely gave up the maintenance of its official library vue resource and directly recommended us to use the axios library

axios packaging steps

1. Install axios

    npm install axios; // Install axios replication code

2. Directory creation

Generally, I will create a new network folder in the src directory of the project as our network request module, and then create a new http JS and an api JS file and a request js. http.js file is used to encapsulate our axios, api JS is used to uniformly manage our interface URL, request JS exposes the api methods we put in.

// At http Introducing axios into JS
import axios from 'axios'; // Introducing axios
import router from '../router';
// The toast prompt box component of vant can be changed according to your own ui components.
import { Toast } from 'vant'; 
//Element UI login, and information prompt
import {Loading, Message} from 'element-ui'

3. Environment switching

Our project environment may include development environment, test environment and production environment. We use the node environment variable to match our default interface url prefix. axios, defaults and baseURL can set the default request address of axios

Create config directory

Directory to create env development. js+env. production. js+env. test. js

env.development.js contents are as follows:

module.exports={
    baseUrl:' http://www.devele.com:4456 '/ / baseurl used in the development environment
}
// Environment switching
const {baseUrl}=require('../config/env.'+process.env.NODE_ENV);

//At the same time, package JSON scripts need to specify the mode of the test environment -- mode test
 "scripts": {
    "serve": "vue-cli-service serve",
    "build": "vue-cli-service build",
    "test": "vue-cli-service build --mode test",
    "lint": "vue-cli-service lint"
  }

const service = axios.create({
  baseURL: baseUrl, // url = base api url + request url
  withCredentials: false, // send cookies when cross-domain requests
  timeout: 1000*12 // request timeout
})

4. Set the request timeout as above

Via Axios defaults. Timeout sets the default request timeout. For example, if it exceeds 10s, the user will be informed of the current request timeout, please refresh, etc.

5.post request header setting

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

// Set post request header

service.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';

6. Request interception

We can intercept a request before sending a request. Why should we intercept it? What do we use to intercept requests? For example, some requests can only be accessed after the user logs in, or when a post request is made, we need to serialize the data we submit. At this time, we can intercept the request before it is sent, so as to carry out the operation we want

// First import vuex, because we need to use the state object inside
// The path of vuex is written according to its own path
import store from '@/store/index';
 
// request interceptor 
service.interceptors.request.use(
  config => {
    // Do not pass. loading is enabled by default
    if (!config.hideloading) {
      // The request is whether to enable loading
      Toast.loading({
        forbidClick: true
      })
    }
      // Judge whether there is a token in vuex before sending a request each time        
        // If it exists, a token will be added to the header of the http request, so that the background can judge your login according to the token
        // Even if there is a token locally, it may be expired, so the return status should be judged in the response interceptor 
    if (store.state.token) {
      config.headers.token = store.state.token;
      //Some interfaces are config headers. Authorization = token
    }
    return config
  },
  error => {
    // do something with request error
    console.log(error) // for debug
    return Promise.reject(error)
  }
)

Let's talk about the token here. Generally, after the login is completed, the user's token is stored locally through localStorage or cookie, and then each time the user enters the page (i.e. in main.js), the token will be read from the local storage first. If the token does not exist and the named user has logged in, the token status in vuex will be updated. Then, every time you request an interface, you will carry a token in the header of the request. The background personnel can judge whether your login has expired according to the token you carry. If you don't carry it, it means you haven't logged in. Many people may have a question? Every request carries a token. What if a page can be accessed without user login? In fact, your front-end request can carry a token, but the background can choose not to accept it

7. Interception of response

// Response interceptor
service.interceptors.response.use(
    response => {   
        // If the returned status code is 200, it indicates that the interface request is successful and the data can be obtained normally     
        // Otherwise, an error is thrown
        if (response.status === 200) {            
            return Promise.resolve(response);        
        } else {            
            return Promise.reject(response);        
        }    
    },    
    // The server status code does not start with 2
    // Here you can negotiate a unified error status code with your background developers    
    // Then perform some operations according to the returned status code, such as login expiration prompt, error prompt, etc
    // Several common operations are listed below, and other requirements can be expanded by themselves
    error => {            
        if (error.response.status) {            
            switch (error.response.status) {                
                // 401: not logged in
                // If you are not logged in, you will jump to the login page and carry the path of the current page
                // After successful login, return to the current page. This step needs to be operated on the login page.                
                case 401:                    
                    router.replace({                        
                        path: '/login',                        
                        query: { 
                            redirect: router.currentRoute.fullPath 
                        }
                    });
                    break;
 
                // 403 token expired
                // Prompt users when login expires
                // Clear local token and empty token object in vuex
                // Jump to login page                
                case 403:
                     Toast({
                        message: 'Login expired, please login again',
                        duration: 1000,
                        forbidClick: true
                    });
                    // Clear token
                  store.dispatch('FedLogOut').then(() => {
                    // Jump to the login page and pass the fullPath of the page to be viewed. After successful login, jump to the page to be visited 
                 router.replace({                            
                            path: '/login',                            
                            query: { 
                                redirect:router.currentRoute.fullPath 
                            }      
                  })      })       
                    break; 
 
                // 404 request does not exist
                case 404:
                    Toast({
                        message: 'The network request does not exist',
                        duration: 1500,
                        forbidClick: true
                    });
                    break;
                // For other errors, directly throw the error prompt
                default:
                    Toast({
                        message: error.response.data.message,
                        duration: 1500,
                        forbidClick: true
                    });
            }
            return Promise.reject(error.response);
        }else {
            // Deal with network disconnection
            // eg: update the network status of state when the request times out or is disconnected
            // network status is in app Vue controls the display and hiding of a global disconnection prompt component
            // The refresh and re acquisition of data in the disconnection component will be described in the disconnection component
            store.commit('changeNetwork', false);
        }

    
});

//Finally, export the instance
export default service;

We understand that we can handle some data before we get the response from the server. For example, the above idea: if the background return status code is 200, then return data normally, otherwise, we need to make some mistakes according to the wrong status code type. In fact, this is mainly an operation of error unified processing and no logon or logon page after logout.

api interface unified management

Create a new api folder with an index js, and multiple interface js files divided according to modules. index.js is an api exit, and other js are used to manage the interfaces of various modules

For example, the following article js:

/**
 * article Module interface list
 */
 
import request from '@/network/http'; // Import the axios instance created in http
import qs from 'qs'; // Whether to import qs module according to requirements
 
const article = {    
    // News list    
    articleList () {        
       return request({
       url: '/artical',
       method: 'get',
       params,
       hideloading: false //Set not to hide loading
    })  
    },    
    // News details, demo    
    articleDetail (id, params) {        
         return request({
		      url: '/detail',
		      method: 'get',
		      params:{
		        goodsId
		      },
		      hideloading: true
		    })
    },
    // post submission    
    login (data) {        
      return request({
      url:'/adduser',
      method:'post',
      data:qs.stringify(data), //Note the data parameter used for post submission
      hideloading: true

     })   
    }
    // Other interfaces
}
 
export default article;

index.js code:

/** 
 * api Unified exit of interface
 */
// Article module interface
import article from '@/api/article';
// Interfaces to other modules
 
// Export interface
export default {    
    article,
    // ......
}

Use in components (import on demand)

import {article} from '@/api/index'

created(){
   article.articleList().then(info=>{
       if(info.code==200)
     this.num=info.data
  }
     })
}

Mount api to vue.com The introduction steps are omitted from prototype

In order to facilitate the call of api, we need to mount it on the prototype of vue in main JS:

import Vue from 'vue'
import App from './App'
import router from './router' // Import routing file
import store from './store' // Import vuex file
import api from './api' // Import api interface
 
Vue.prototype.$api = api; // Mount the api on the prototype of vue and copy the code

You can then use in the component:

//No import required
methods: {    
    onLoad(id) {      
        this.$api.article.articleDetail(id, {        
            api: 123      
        }).then(res=> {
            // Perform some actions      
        })    
    }  
}

Handling of network disconnection

The following app Vue NEW

<template>  
    <div id="app">    
        <div v-if="!network">      
            <h3>I have no Internet</h3>      
            <div @click="onRefresh">Refresh</div>      
        </div>    
        <router-view/>      
    </div>
</template>
 
<script>
    import { mapState } from 'vuex';
    export default {  
        name: 'App',  
        computed: {    
            ...mapState(['network'])  
        },  
        methods: {    
            // Refresh the current page data by jumping to an empty page and returning
            onRefresh () {      
                this.$router.replace('/refresh')    
            }  
        }
    }
</script>

This is app vue, here is a brief demonstration of disconnection. At http JS describes that we will update the network status in vue when the network is disconnected. Here, we judge whether to load the disconnected component according to the network status. When the network is disconnected, the disconnected components are loaded, and the components of the corresponding page are not loaded. When we click refresh, we can retrieve the data by jumping to the refresh page and returning immediately. So we need to create a new refresh vue page and return to the current page in its beforeRouteEnter hook.

// refresh.vue
beforeRouteEnter (to, from, next) {
    next(vm => {            
        vm.$router.replace(from.fullPath)        
    })    
}

Keywords: Vue

Added by nschmutz on Thu, 03 Feb 2022 07:13:03 +0200