Hands package axios

Gangster link:

https://juejin.im/post/5b55c118f265da0f6f1aa354

A, axios package

In vue project, and get the data back this interaction, we usually use the axios library, which is based on the promise of http library, you can run in the browser and node.js in. He has a lot of excellent features, such as intercepting requests and responses, cancellation request, convert json, clients and other defense XSRF. So we are also determined to give up much, especially the maintenance of its official repository vue-resource directly recommend we use axios library. If you do not understand axios also be the venue axios document .

installation

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

Introduced

In general I would src directory of the project, request a new folder, and then create a new http.js a api.js file inside. http.js file is used to package our axios, api.js to our unified management interface.

 

 

 

 

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

Switching environment

Our project environment may have development, test and production environments. We have to match our default interface url prefixed by the environment variable node. axios.defaults.baseURL can set the default axios request address will not say more.

 

 

 

 

// 环境的切换
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

Axios.defaults.timeout by setting default request timeout. For example, more than the 10s, it will inform the user of the current request timed out, please refresh and so on.

 

 

 

 

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

post request header set

When post requests, we need to add a request headers, so it can be a default setting here, that is set to post the request headerapplication/x-www-form-urlencoded;charset=UTF-8

 

 

 

 

axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;charset=UTF-8';复制代码
  • Request Interceptor

We can intercept the request before sending a request, why should intercept it, we requested to intercept what it used to do? For example, some requests are required after the user logged in to visit, or when the post request, we need to serialize the data we submitted. At this time, we can intercept before a request is sent, so we want to operate.

Request Interceptor

 

 

 

 

// 先导入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);    
})
复制代码

Said here about token, usually after the registration is completed, the user's token presence locally through localStorage or cookie, then every time a user when entering the page (ie main.js in), first reads the token from local store If there is token describes the user has landed, token status vuex in is updated. Then, each time the request interface, will be carried in the header of the request token, back office staff can judge your login has expired according to your portable token, if there is no carry, then not logged in. This time may be some small partners have questions, that is, each request carries token, then how to do, if a page does not require user login you can access it? In fact, you can request the front carry token, but the background may choose not to receive ah!

Interception response

 

 

 

 

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

In response interceptor well understood, is the server returned to our data, we can do some work for him to get in before. Such as the above idea: If the background returned status code is 200, then the data is returned properly, otherwise some errors we need following an error status code types, in fact, this is mainly made false unity deal and did not sign in or sign expired adjusted operating a login page.

It should be noted that the above Toast () method, are vant library I introduced the toast lightly prompt components, based on your ui library, corresponding to a prompt use your components.

 

Packaging get and post method

 

There are get, post, put and other methods we used ajax request method, we believe that small partners are not unfamiliar. axios corresponding there are many similar approach may look unclear documentation. But in order to simplify our code, we still have to be a simple package. Here we package two main methods: get and post.

get method : we get a function defined by, the get function has two parameters, the first parameter represents the url we want to request the second parameter is a parameter request to be carried our. function returns the object get a promise, when axios successfully resolve it requests the server returns the value, reject the request fails error value. Finally get thrown function 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 with get, it should be noted that, post submission method must be used to operate from the parameter object serialization, so here we have to serialize our parameters of qs node module. This is very important, if not the sequence of operation, the background is that you can not get the data submitted. This is what we import QS from 'qs' beginning of the article; reason. If you do not understand what is the meaning of serialization, to Baidu about it, the answer is a lot.

 

 

 

 

/** 
 * 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)
        })
    });
}复制代码

There is a small detail to the next, axios.get()methods, and axios.post()writing style parameters at the time of submission of data is still a difference. Difference is that the second parameter is a get {}, then params object attribute value is a parameter object. The second parameter is a post parameter object. A slight difference between the two should pay attention to Oh!

 

axios basic package is complete, then the following simply under the unified management api's.

Api as neat as a circuit board, even the most complex can clear the entire circuit. Above that, we will create a new api.js, then store all of our api interfaces in this document.

  • First we get and post method we introduced the package in the api.js

 

 

 

 

/**   
 * api接口统一管理
 */
import { get, post } from './http'复制代码

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

 

 

 

 

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

We can package in api.js in:

 

 

 

 

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

We define a apiAddressmethod that has a parameter p, p is the parameter object carried our request interface. Then we call the package postmethod, postthe first parameter is the method of our interface address, the second parameter is apiAddressa parameter p, i.e. parameter object carried request interface. Finally, export exported through apiAddress.

Then our page can call our api interfaces:

 

 

 

 

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

Other interfaces api, to continue to expand on it in the following pai.js in. Tips, written comments for each interface Oh! ! !

One of the benefits api interface management is that we put together a unified api, if the latter need to modify the interface, we find the corresponding modified directly in api.js just fine, without having every page to find our interface and then modify It will be very troublesome. The key is, if the modified larger than, on the specification gg. If there is to modify the interface, believe in our direct business code also easy to move our business code to cause unnecessary trouble.

 

Well, the last to complete the package code axios offer.

 

 

 

/**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) }) }); } 复制代码

 

 

If you like, give it a ❤❤ (* ^ ▽ ^ *)

 

********* ****************** gorgeous gorgeous dividing line dividing line ************* ***** gorgeous gorgeous dividing line dividing line ***************** ****************** gorgeous dividing line ********* *

2018.8.14 update

axios package according to the different needs of different. Thank you very much the comments here some very sound advice, and I think this has been improved and for different needs. Mainly in the following changes:

1. Optimize axios package, and get removed before the post

2. disconnection case processing

3. more modular management api

4. Interface with a plurality of domain name

5.api mounted to omit the step of introducing the vue.prototype

 

In axios encapsulated optimization http.js, directly attached to the code:

 

 

 

 

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

/** 
 * 提示函数 
 * 禁止点击蒙层、显示一秒后关闭
 */
const tip = msg => {    
    Toast({        
        message: msg,        
        duration: 1000,        
        forbidClick: true }); } /** * 跳转登录页 * 携带当前页面路由,以期在登录页面完成登录后返回当前页面 */ const toLogin = () => { router.replace({ path: '/login', query: { redirect: router.currentRoute.fullPath } }); } /** * 请求失败后的错误统一处理 * @param {Number} status 请求失败的状态码 */ const errorHandle = (status, other) => { // 状态码判断 switch (status) { // 401: 未登录状态,跳转登录页 case 401: toLogin(); break; // 403 token过期 // 清除token并跳转登录页 case 403: tip('登录过期,请重新登录'); localStorage.removeItem('token'); store.commit('loginSuccess', null); setTimeout(() => { toLogin(); }, 1000); break; // 404请求不存在 case 404: tip('请求的资源不存在'); break; default: console.log(other); }} // 创建axios实例 var instance = axios.create({ timeout: 1000 * 12}); // 设置post请求头 instance.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded'; /** * 请求拦截器 * 每次请求前,如果存在token则在请求头中携带token */ instance.interceptors.request.use( config => { // 登录流程控制中,根据本地是否存在token判断用户的登录情况 // 但是即使token存在,也有可能token是过期的,所以在每次的请求头中携带token // 后台根据携带的token判断用户的登录情况,并返回给我们对应的状态码 // 而后我们可以在响应拦截器中,根据状态码进行一些统一的操作。 const token = store.state.token; token && (config.headers.Authorization = token); return config; }, error => Promise.error(error)) // 响应拦截器 instance.interceptors.response.use( // 请求成功 res => res.status === 200 ? Promise.resolve(res) : Promise.reject(res), // 请求失败 error => { const { response } = error; if (response) { // 请求已发出,但是不在2xx的范围 errorHandle(response.status, response.data.message); return Promise.reject(response); } else { // 处理断网的情况 // eg:请求超时或断网时,更新state的network状态 // network状态在app.vue中控制着一个全局的断网提示组件的显示隐藏 // 关于断网组件中的刷新重新获取数据,会在断网组件中说明 if (!window.navigator.onLine) { store.commit('changeNetwork', false); } else { return Promise.reject(error); } } }); export default instance;复制代码
This axios and before the similar, made a few changes as follows:

1. removed prior to encapsulation methods get and post, axios instance by creating a method of deriving and export default, so that more flexible use.

2. The value of the control baseUrl removed by the environment variable. Taking into account the different interfaces have multiple domain names, so be prepared to control the interface via js variable domain. This will be introduced in particular in the api.

3. increase request times out, i.e., off-network state process. Said that under the idea, when off the network, by updating the status of the network to control vuex show hidden prompt disconnection component. Tip off the network usually have to reload the operating data, where this step will be described later in correspondence.

4. The common extraction function, to simplify the code, try to ensure that the principle of the single functions.

 

Below that under this api, you need to consider:

1. more modular

2. easier for people to develop, effective solution to reduce naming conflicts

3. Process Interface have multiple domain case

Here here it created a new api folder, which has a index.js and a base.js, and multiple interfaces js file module is divided according to. index.js is a api export, base.js domain management interface, other js is used to manage the interface of each module.

First put index.js Code:

 

 

 

 

/** 
 * api接口的统一出口
 */
// 文章模块接口
import article from '@/api/article';
// 其他模块的接口……

// 导出接口
export default {    
    article,
    // ……
}复制代码

index.js exports a api interface, so you can put api interfaces according to the function is divided into multiple modules, which will help people collaborate to develop such a person is only responsible for the development of a module, etc., but also to facilitate each module interface named oh.

base.js:

 

 

 

 

/**
 * 接口域名的管理
 */
const base = {    
    sq: 'https://xxxx111111.com/api/v1',    
    bd: 'http://xxxxx22222.com/api'
}

export default base;复制代码

Our interface to manage domain names through base.js, no matter how many may have defined interfaces through here. Even amend it, it is also very convenient.

Finally, described is the interface module, such as the above article.js:

 

 

 

 

/**
 * article模块接口列表
 */

import base from './base'; // 导入接口域名列表
import axios from '@/utils/http'; // 导入http中创建的axios实例
import qs from 'qs'; // 根据需求是否导入qs模块

const article = {    
    // 新闻列表    
    articleList () { return axios.get(`${base.sq}/topics`); }, // 新闻详情,演示 articleDetail (id, params) { return axios.get(`${base.sq}/topic/${id}`, { params: params }); }, // post提交 login (params) { return axios.post(`${base.sq}/accesstoken`, qs.stringify(params)); } // 其他接口………… } export default article;复制代码

1. We packaged by direct introduction Axios example, then the definition of the interface, and return calls Axios example, more flexible use of Axios, for example, you can submit data when processing a sequence of requests for qs post like.

2. Request the configuration is more flexible, you can make a different configuration for certain requirements. About a priority, axios document says very clearly that this order is: the lib/defaults.jsdefault values found in the library, then is an instance of defaultsproperty, and finally the request configparameters. The latter will take precedence over the former.

3.restful style interface can also be flexible setup api interface addresses this way.

Finally, in order to facilitate the call api, we need to mount it to the prototype vue. In main.js in:

 

 

 

 

import Vue from 'vue'
import App from './App'
import router from './router' // 导入路由文件
import store from './store' // 导入vuex文件
import api from './api' // 导入api接口 Vue.prototype.$api = api; // 将api挂载到vue的原型上复制代码

Then we can call the interface on the page, eg:

 

 

 

 

methods: {    
    onLoad(id) {      
        this.$api.article.articleDetail(id, {        
            api: 123      
        }).then(res=> {
            // 执行某些操作      
        })    
    }  
}复制代码

Mention about handling broken network, where only a simple example:

 

 

 

 

<template>  
    <div id="app">    
        <div v-if="!network">      
            <h3>我没网了</h3>      
            <div @click="onRefresh">刷新</div>      
        </div>    
        <router-view/>      
    </div>
</template>

<script>
    import { mapState } from 'vuex';
    export default { name: 'App', computed: { ...mapState(['network']) }, methods: { // 通过跳转一个空页面再返回的方式来实现刷新当前页面数据的目的 onRefresh () { this.$router.replace('/refresh') } } } </script>复制代码

This is app.vue, here a brief presentation about the broken network. Introduced in http.js, we will break when the network, to update the status of the network vue, then here we need to determine whether the load off the network components according to the state of the network. Off the network, the load off the network component, the component does not load the corresponding page. When click refresh, and then we immediately return to be achieved by way of the jump page refesh retrieve operational data. So we need to create a refresh.vue page, and its beforeRouteEnterback hook in the current page.

 

 

 

 

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

This is a global general tips off network, of course, it can also operate according to their project requirements. For details on the eyes of the beholder wise see wisdom.

If more demand, or demand is not the same, it may be a modified according to their needs.

 

If you feel you have to help, then quickly to focus on the big brother now!

https://juejin.im/post/5b55c118f265da0f6f1aa354

Guess you like

Origin www.cnblogs.com/ll15888/p/11872694.html