Explicar en detalle la encapsulación de axios y la gestión de encapsulación de la interfaz api

I. Introducción


De hecho, el principal objetivo del encapsulado de axios y la gestión unificada de la interfaz API es ayudarnos a simplificar el código y facilitar su posterior actualización y mantenimiento.

En el proyecto vue, generalmente usamos la biblioteca axios para interactuar con el fondo para obtener datos, que es una biblioteca http basada en promesas que puede ejecutarse en el navegador y node.js. Tiene muchas características excelentes, como interceptar solicitudes y respuestas, cancelar solicitudes, convertir json, defensa del lado del cliente contra XSRF, etc. Entonces, nuestro Youda también renunció decisivamente al mantenimiento de su biblioteca oficial vue-resource y nos recomendó directamente que usáramos la biblioteca axios.

2. Pasos de empaquetado de Axios

  1. instalar axios
    npm install axios -S; // 安装axios复制代码

1. Creación de directorio

En general, crearé una carpeta de red en el directorio src del proyecto como nuestro módulo de solicitud de red y luego crearé un archivo http.js, un archivo api.js y una solicitud.js en él. El archivo http.js se usa para encapsular nuestros axios, el api.js se usa para administrar la URL de nuestra interfaz de manera unificada y el request.js expone el método api que colocamos.

// 在http.js中引入axios
import axios from 'axios'; // 引入axios
import router from '../router';
// vant的toast提示框组件,大家可根据自己的ui组件更改。
import { Toast } from 'vant'; 

  1. Cambio de entorno

Nuestro entorno de proyecto puede tener un entorno de desarrollo, un entorno de prueba y un entorno de producción. Usamos variables de entorno de nodo para que coincidan con nuestro prefijo de URL de interfaz predeterminado. Axios.defaults.baseURL puede establecer la dirección de solicitud predeterminada de axios, por lo que no diré mucho.

Cree un directorio de configuración. Creado bajo el directorioenv.development.js+env.production.js+env.test.js

env.development.jsEl contenido es el siguiente:

module.exports={
    baseUrl:' http://www.devele.com:4456' //开发环境用到的baseurl
}

// 环境的切换
const {baseUrl}=require('../config/env.'+process.env.NODE_ENV);
//同时 package.json的scripts需指定测试环境的模式  --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 // 请求超时
})

4. Establezca el tiempo de espera de la solicitud como se indicó anteriormente

Establezca el tiempo de espera de solicitud predeterminado a través de axios.defaults.timeout. Por ejemplo, si supera los 10 s, se notificará al usuario que la solicitud actual ha expirado, actualice, etc.

  1. Al configurar el encabezado de solicitud de publicación, debemos agregar un encabezado de solicitud, por lo que podemos hacer una configuración predeterminada aquí, es decir, establecer el encabezado de solicitud de publicación enapplication/x-www-form-urlencoded;charset=UTF-8
// 设置post请求头
service.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';

  1. solicitud de intercepción

Podemos interceptar una solicitud antes de enviarla. ¿Por qué debemos interceptarla? ¿Qué estamos usando para interceptar la solicitud? Por ejemplo, solo se puede acceder a algunas solicitudes después de que el usuario inicia sesión, o cuando publicamos una solicitud, necesitamos serializar los datos que enviamos. En este momento, podemos interceptar la solicitud antes de que se envíe, para realizar la operación que queremos.

// 先导入vuex,因为我们要使用到里面的状态对象
// vuex的路径根据自己的路径去写
import store from '@/store/index';
// 请求拦截器
service.interceptors.request.use(
  config => {
    // 不传递默认开启loading
    if (!config.hideloading) {
      // 请求是是否开启loading
      Toast.loading({
        forbidClick: true
      })
    }
      // 每次发送请求之前判断vuex中是否存在token        
        // 如果存在,则统一在http请求的header都加上token,这样后台根据token判断你的登录情况
        // 即使本地存在token,也有可能token是过期的,所以在响应拦截器中要对返回状态进行判断 
    if (store.state.token) {
      config.headers.token = store.state.token;
      //有些接口是 config.headers.Authorization = token
    }
    return config
  },
  error => {
    // do something with request error
    console.log(error) // for debug
    return Promise.reject(error)
  }
)

Hablemos de token aquí. Generalmente, después de que se completa el inicio de sesión, el token del usuario se almacena localmente a través de localStorage o cookie, y luego, cada vez que el usuario ingresa a la página (es decir, en main.js), primero leerá el token desde el almacenamiento local. , si existe el token, lo que indica que el usuario ya ha iniciado sesión, actualice el estado del token en vuex. Luego, cada vez que solicite la interfaz, el token se llevará en el encabezado de la solicitud, y el personal de antecedentes puede juzgar si su inicio de sesión ha caducado en función del token que lleva. Si no se lleva, significa que tiene Sin iniciar sesión. En este momento, algunos amigos pueden tener dudas, es decir, cada solicitud lleva un token, ¿y si se puede acceder a una página sin el inicio de sesión del usuario? De hecho, su solicitud de front-end puede llevar un token, ¡pero el fondo puede optar por no recibirlo!

  1. intercepción de respuesta
// 响应拦截器
service.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
                  store.dispatch('FedLogOut').then(() => {
                    // 跳转登录页面,并将要浏览的页面fullPath传过去,登录成功后跳转需要访问的页面 
                 router.replace({                            
                            path: '/login',                            
                            query: { 
                                redirect:router.currentRoute.fullPath 
                            }      
                  })      })       
                    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);
        }else {
            // 处理断网的情况
            // eg:请求超时或断网时,更新state的network状态
            // network状态在app.vue中控制着一个全局的断网提示组件的显示隐藏
            // 关于断网组件中的刷新重新获取数据,会在断网组件中说明
            store.commit('changeNetwork', false);
        }    
});
//最后导出实例
export default service;

El interceptor de respuesta se entiende bien, es decir, los datos que nos devuelve el servidor, podemos procesarlos antes de obtenerlos. Por ejemplo, la idea anterior: si el código de estado devuelto por el fondo es 200, devolver los datos normalmente, de lo contrario, cometer algunos errores que necesitamos según el tipo de código de estado incorrecto. De hecho, aquí hay principalmente una operación de ajuste del página 错误的统一处理de inicio de 没登录sesión登录过期

En este punto, la encapsulación de axios está básicamente completa, hablemos brevemente sobre la gestión unificada de api.

3. Gestión unificada de la interfaz api

Creó una nueva carpeta api, que contiene un index.js y varios archivos js de interfaz divididos según los módulos. index.js es una exportación de API, y otro js se usa para administrar la interfaz de cada módulo.

Por ejemplo, el siguiente artículo.js:

/**
 * article模块接口列表
 */
import request from '@/network/http'; // 导入http中创建的axios实例
import qs from 'qs'; // 根据需求是否导入qs模块 
const article = {    
    // 新闻列表    
    articleList () {        
       return request({
       url: '/artical',
       method: 'get',
       params,
       hideloading: false //设置不隐藏加载loading
    })  
    },    
    // 新闻详情,演示    
    articleDetail (id, params) {        
         return request({
		      url: '/detail',
		      method: 'get',
		      params:{
		        goodsId
		      },
		      hideloading: true
		    })
    },
    // post提交    
    login (data) {        
      return request({
      url:'/adduser',
      method:'post',
      data:qs.stringify(data), //注意post提交用data参数
      hideloading: true
     })   
    }
    // 其他接口…………
}
export default article;

código index.js:

/** 
 * api接口的统一出口
 */
// 文章模块接口
import article from '@/api/article';
// 其他模块的接口…… 
// 导出接口
export default {    
    article,
    // ……
}

Uso en componentes (importación bajo demanda)

import {article} from '@/api/index'
created(){
   article.articleList().then(info=>{
       if(info.code==200)
     this.num=info.data
  }
     })
}

La API está montada en vue.prototype para guardar los pasos de introducción.

Para facilitar la llamada de API, debemos montarla en el prototipo de vue. En main.js:

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的原型上复制代码

Entonces podemos usar esto en el componente

//无需导入
methods: {    
    onLoad(id) {      
        this.$api.article.articleDetail(id, {        
            api: 123      
        }).then(res=> {
            // 执行某些操作      
        })    
    }  
}


Manejo de la desconexión de la red

Agregue la siguiente aplicación.vue

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

Esto es app.vue, aquí hay una breve demostración de desconexión. Introducido en http.js, actualizaremos el estado de la red en vue cuando la red esté desconectada, por lo que aquí juzgamos si cargamos el componente desconectado de acuerdo con el estado de la red. Cuando la red está desconectada, el componente desconectado se carga y el componente de la página correspondiente no se carga. Al hacer clic en actualizar, nos damos cuenta de la operación de volver a adquirir datos saltando a la página de actualización y luego regresando inmediatamente. Por lo tanto, debemos crear una nueva página refresh.vue y volver a la página actual en su enlace beforeRouteEnter.

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

Supongo que te gusta

Origin blog.csdn.net/onebound_linda/article/details/131001264
Recomendado
Clasificación