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) }) }