当前位置 博文首页 > 丶Serendipity丶:vue-axios的总结及项目中的常见封装方法。

    丶Serendipity丶:vue-axios的总结及项目中的常见封装方法。

    作者:丶Serendipity丶 时间:2021-05-09 18:19

    前言

      我们知道 vue 2.0版本开始推荐使用 axios 来完成前端 ajax 请求,axios 是一个基于Promise 的 http 库,可以用在浏览器和 node.js 中,axios 成为vue全家桶的一个重要部分,对前后端接口请求起着必不可少的作用,本文主要总结一下 axios 的一些小知识点和项目中常见的需要封装的方法。

    正文

      1.axios 是什么?

      axios 是一个基于 Promise 的 http 库,可以用于浏览器和 node.js 中,在浏览器中创建 XMLHttpRequest 对象(基于ajax的一种封装),然后调用该对象的一些方法实现对后端数据接口的请求,在 node.js 中用于创建 http 请求,支持 Promise Api,可以使用 async/await 语法糖书写,便于拦截请求和响应,并对请求和响应的数据进行处理,自动转换 JSON 数据格式,同事用于客户端支持防御 XSRF。且目前主流浏览器都支持该库。

      常见的安装方式有以下两种:

      (1)使用 cdn 方式,代码中直接引入下面脚本即可,这种方式适用于小型项目,比如学习的小 demo 等。

        <script src="https://unpkg.com/axios/dist/axios.min.js"></script>

     

      (2)使用 npm 方式,直接在命令行中添加即可。

        npm install axios

     

      2.axios 常见用法?

      axios中常用的请求配置如下,只有指定的url是必须项,其他存在默认配置项,method不特殊指定,默认方法为 get 。

      {
        url: '/user',
      // `url` 是用于请求的服务器 URL    method: 'get',
      // default `method` 是创建请求时使用的方法    baseURL: 'https://some-domain.com/api/',
      // `baseURL` 将自动加在 `url` 前面,除非 `url` 是一个绝对 URL。它可以通过设置一个 `baseURL` 便于为 axios 实例的方法传递相对 URL   headers: {'X-Requested-With': 'XMLHttpRequest'},
      // `headers` 是即将被发送的自定义请求头   params: {   ID: 12345   },
      // 必须是一个无格式对象(plain object)或 URLSearchParams 对象,`params` 是即将与请求一起发送的 URL 参数   timeout: 1000,
      // 如果请求话费了超过 `timeout` 的时间,请求将被中断,`timeout` 指定请求超时的毫秒数(0 表示无超时时间)   withCredentials: false,
      // default `withCredentials` 表示跨域请求时是否需要使用凭证    responseType: 'json',
      // default `responseType` 表示服务器响应的数据类型,可以是 'arraybuffer', 'blob', 'document', 'json', 'text', 'stream'    responseEncoding: 'utf8', // default   onUploadProgress: function (progressEvent) {
      // `onUploadProgress` 允许为上传处理进度事件   // Do whatever you want with the native progress event    },    onDownloadProgress: function (progressEvent) {
      // `onDownloadProgress` 允许为下载处理进度事件   // 对原生进度事件的处理    },   }

      (1)get 请求

     

        axios.get('url',{params:{
            //这里是请求参数
        }})
        .then(res=>{
        //这里是响应后操作 }) .
    catch(err=>{
        //异常捕获 })

     

      (2)post 请求

        axios.post('url',{  
            name:xxx//参数  
        },{  
            headers:xxxx,//请求头信息
        })
        .then(function(res){  
            //处理成功的函数 相当于success
        })
        .catch(function(error){  
            //错误处理 相当于error
        })

      (3)all、spread 并发请求

        axios.all([
        axios.get('url'),
        axios.get('url',{params:{type:'sell',page:1}})
        ])
        .then(axios.spread((res1,res2)=>{
            //返回结果为一个数组
        }))

      all()方法入参为一个数组,数组元素是每一项请求,回调函数 .then() 的参数也是一个数组,里面的每一项元素表示前面请求的返回结果,使用了 axios.spread作为该回调函数的参数时,其res1,res2分别代表前面每一项请求的返回结果。

      综上这些方法都只使用于小型项目中,或者学习小 demo 中,在工作开发中遇到处理的请求接口较多,

     

      3.axios 在项目中的常见用法?

      (1)小型项目中常见封装方法,灵活性较高。

      首先创建 axios.js 文件

     

         import originAxios from 'axios'
        export default  function axios(option){
            return new Promise((resolve,reject)=>{
                //创建axios实例
                const instance=originAxios.create({
                    baseURL:'/api',
                    timeout:5000,
                    headers:''
                });
                //传入对象进行网络请求
                instance(option)
                .then(res=>{
                    resolve(res)
                })
                .catch(err=>{
                    reject(err)
                })
            })
        }

     

      然后在需要发送请求接口的地方引入

        import {axios} from './axios.js'
    
        axios({method:"get",url:"url",params:{...}})
        .then(res=>{
            //请求数据后操作
        })
        .catch(err=.{
            //错误处理
        })    

     

      (2)针对不同请求类型进行二次封装。

     

        /* *url:请求的url
           *params:请求的参数
           *config:请求时的header信息
           *method:请求方法 */
          const request = function ({ url, params, config, method }) {
            // 如果是get请求 需要拼接参数
            let str = "";
            if (method === "get" && params) {
              Object.keys(params).forEach((item) => {
                str += `${item}=${params[item]}&`;
              });
            }
            return new Promise((resolve, reject) => {
              axios[method](
                str ? url + "?" + str.substring(0, str.length - 1) : url,
                params,
                Object.assign({}, config)
              )
                .then(
                  (response) => {
                    resolve(response.data);
                  },
                  (err) => {
                    if (err.Cancel) {
                    } else {
                      reject(err);
                    }
                  }
                )
                .catch((err) => {
                  reject(err);
                });
            });
          };

     

      具体使用同上。

      (3)基于请求响应拦截进行封装,实际项目开发中常用。

      axios 提供的拦截器,用于每次发送请求和得到响应后进行响应的处理。比如在请求拦截中可以在页面中添加 loading 动画,某些请求要求用户必须登录,判断用户是否有token,如果没有就跳转到登录页面等,也可以对请求参数进行序列化操作等 config.data = qs.stringfy(config.params) 等。同样,响应拦截也可以对响应的数据进行过滤,包括响应失败的拦截,可以根据响应状态码进行不同的操作等。具体方法如下:

      首先在工具方法文件夹中创建 request.js 文件。这里搭配了token用于判断用户状态,element-ui 组件处理一些错误报错提示。该文件封装暴露了get、post、文件上传方法。

     

          import axios from "axios";
          import store from "../store";
          import { Message, MessageBox } from "element-ui";
    
          let baseURL = "http://127.0.0.1:3000/";
          // 创建axios实例
          const service = axios.create({
            baseURL: baseURL,
            timeout: 5000, // 请求超时时间
            headers: { "Content-Type": "application/json;charset=UTF-8" },
          });
          // axios.defaults.withCredentials = true; // 若跨域请求需要带 cookie 身份识别
          axios.defaults.headers.post["Access-Control-Allow-Origin-Type"] = "*"; // 允许跨域
          const err = (error) => {
            if (error.response) {
              let data = error.response.data;
              const token = store.getters.token;
              switch (error.response.status) {
                case 403:
                  Message({
                    message: data.message,
                    type: "error",
                    duration: 5 * 1000,
                  });
                  break;
                case 500:
                  if (token && data.message == "Token失效,请重新登录") {
                    MessageBox.confirm(
                      "很抱歉,登录已过期,请重新登录",
                      "确定登出",
                      {
                        confirmButtonText: "重新登录",
                        cancelButtonText: "取消",
                        type: "warning",
                      }
                    ).then(() => {
                      store.dispatch("Logout").then(() => {
                        window.location.reload(); // 为了重新实例化vue-router对象 避免bug
                      });
                    });
                  }
                  break;
                case 404:
                  Message({
                    message: data.message,
                    type: "error",
                    duration: 5 * 1000,
                  });
    
                  break;
                case 504:
                  Message({
                    message: data.message,
                    type: "error",
                    duration: 5 * 1000,
                  });
                  break;
                case 401:
                  Message({
                    message: data.message,
                    type: "error",
                    duration: 5 * 1000,
                  });
                  if (token) {
                    store.dispatch("Logout").then(() => {
                      setTimeout(() => {
                        window.location.reload();
                      }, 1500);
                    });
                  }
                  break;
                default:
                  Message({
                    message: data.message,
                    type: "error",
                    duration: 5 * 1000,
                  });
                  break;
              }
            }
            return Promise.reject(error);
          };
          // request拦截器
          service.interceptors.request.use(
            (config) => {
              const token = store.getters.token;
              if (store.getters.token) {
                config.headers["X-Token"] = token;
              }
              return config;
            },
            (error) => {
              // Do something with request error
              console.log(error); // for debug
              Promise.reject(error);
            }
          );
          // respone拦截器
          service.interceptors.response.use((response) => {
            console.log("response.data", response.data);
            return response.data;
          }, err);
    
          /*
           *  get请求
           *  url:请求地址
           *  params:参数
           * */
          export function get(url, params = {}) {
            return new Promise((resolve, reject) => {
              console.log("process.env.BASE_API", process.env.BASE_API);
              service({
                url: url,
                method: "get",
                params: params,
              })
                .then((response) => {
                  resolve(response);
                })
                .catch((error) => {
                  reject(error);
                });
            });
          }
    
          /*
           *  post请求
           *  url:请求地址
           *  params:参数
           * */
          export function post(url, params = {}) {
            return new Promise((resolve, reject) => {
              service({
                url: url,
                method: "post",
                data: params,
              })
                .then((response) => {
                  resolve(response);
                })
                .catch((error) => {
                  reject(error);
                });
            });
          }
    
          /*
           *  文件上传
           *  url:请求地址
           *  params:参数
           * */
          export function fileUpload(url, params = {}) {
            return new Promise((resolve, reject) => {
              console.log("@@@@@@@@@@@params", params);
              service({
                url: url,
                method: "post",
                data: params,
                headers: { "Content-Type": "multipart/form-data" },
              })
                .then((response) => {
                  resolve(response);
                })
                .catch((error) => {
                  reject(error);
                });
            });
          }
    
          export default {
            get,
            post,
            fileUpload,
          };

     

      然后创建api文件夹,如果接口过多可以对接口进行模块化管理,比如我这 api 下面创建 login.js 文件。

    import { get, post,fileUpload } from "../utils/request";
    
    // 登录
    export const login = (params) => {
      return get("/user/login", { ...params });
    };
    // 查询用户信息
    export const getUserInfo = (params) => {
      return get("/user/userInfo", { ...params });
    };
    // 上传音频文件
    export const addRadioApi = (params, file) => {
      return fileUpload("/radio/addRadio", { params, file });
    };

      最后在你的vue文件中就可以使用了,login.vue中使用如下:

          import { login } from "../../api/login";
          login({ name: "123", password: "123456" })
            .then((res) => {
              //登录请求后操作
            })
            .catch((error) => {
              //异常处理
            });

    总结

      以上就是本文的全部内容,希望给读者带来些许的帮助和进步,方便的话点个关注,小白的成长踩坑之路会持续更新一些工作中常见的问题和技术点。

     

    bk