手把手带你在vue中封装axios(含携带token)

news/2024/7/10 3:01:03 标签: vue, js, ajax

文章目录

  • 前言
  • 一、认识axios
    • 1、axios是什么?
    • 2、为什么要用axios?
      • 特性
  • 二、封装axios
    • 1.引入库
    • 2.建立封装axios实例文件
    • 3.导入所需依赖
    • 4.创建axios实例
    • 5.axios拦截器
      • 请求拦截器
      • 响应拦截器
    • 5.封装成请求
    • 6.完整代码
      • 代码
      • 代码中的setLocalStorage和getLocalStorage方法
        • setLocalStorage
        • getLocalStorage
  • 总结


前言

在前端的高速发展下,单页面应用大多采用前后端分离的开发思路,现在帮助前后端交互的工具数不胜数,axios无疑是当今最受欢迎的http库,但是你真的玩透了axios吗?接下来,我们将一起进行一次axios的封装体验,做出属于自己的axios。(本次封装演示建立Vue项目中)

一、认识axios

此环节带领大家了解axios,如果熟练的同学可直接移步到下面的封装环节哦!

1、axios是什么?

官方解释:

Axios 是一个基于 promise 的 HTTP 库,可以用在浏览器和 node.js 中。

2、为什么要用axios?

axios最大的亮点就是它支持了ES6里的 Promise Api,感兴趣的同学可以去看一看阮一峰写的 《ES6入门教程》,传送门:ES6入门教程

特性

  • 从浏览器中创建 XMLHttpRequests
  • 从 node.js 创建 http 请求
  • 支持 Promise API
  • 拦截请求和响应
  • 转换请求数据和响应数据
  • 取消请求
  • 自动转换 JSON 数据
  • 客户端支持防御 XSRF

废话不多说,我们直接开始!

二、封装axios

1.引入库

使用npm

$ npm install axios

使用yarn

$ yarn add axios

使用bower

$ bower install axios

2.建立封装axios实例文件

因为项目一般都是工程化,所以我们得建立一个文件来单独封装axios,这样才能更加清晰。

通常我们在项目src目录下新建utils文件夹,然后在其中新建 request.js文件,这个文件是主要书写axios的封装过程。

3.导入所需依赖

// 导入axios
import axios from 'axios'
// 导入element的message组件
import { Message } from 'element-ui'
// 导入其他文件里的localStorage方法(操作token时用到,后面将给出详细代码)
import { setLocalStorage,getLocalStorage } from '@/utils/utils'

4.创建axios实例

首先,我们根据文档提供的create方法新建一个axios实例

const instance = axios.create({
  // baseURL 将自动加在 url`前面,除非 url 是一个绝对 URL。
  // 它可以通过设置一个 baseURL 便于为 axios 实例的方法传递相对 URL
  baseURL: baseUrl,
  // timeout设置一个请求超时时间,如果请求时间超过了timeout,请求将被中断,单位为毫秒(ms)
  timeout: 60000,
  // headers是被发送的自定义请求头,请求头内容需要根据后端要求去设置,这里我们使用本项目请求头。
  headers: {
    'Accept': 'application/json',
    'Content-Type': 'application/json'
  }
})

如果你想使用原生的axios并且设置全局的axios的时候。你也可以用以下这种方法进行配置,比如:

// 这里设置了axios的全局baseURL地址,其他也可类似这样进行设置
axios.defaults.baseURL = 'https://api.example.com';

5.axios拦截器

为什么需要拦截器呢?

  • 当你在发起request请求前想做一些事时,比如携带token,或者处理请求错误。
  • 当你在接受response前想做一些事时,比如处理错误码,数据过滤。

请求拦截器

// http request 请求拦截器
instance.interceptors.request.use(
  config => {
    // 这里判断localStorage里面是否存在token,如果有则在请求头里面设置
    if (localStorage.jwtToken) {
      config.headers.Authorization = getLocalStorage("jwtToken");
    }
    return config
  },
  err => {
    return Promise.reject(err)
  }
)

在这里插入图片描述
vscode的提示告诉我config是个这个东西

相信大家和我一样对config具体是个什么东西有点好奇,话不多说,让我们打印看看它是什么妖魔鬼怪吧。

在这里插入图片描述
可以看出,这就是我们用axios封装的请求配置,里面有我们之前设置的baseURL,有headers和timeout等参数。

响应拦截器

// http response 响应拦截器
instance.interceptors.response.use(
  response => {
  // 这里对响应的数据做了操作,大家可以自己设置响应过滤哦,下面会给出具体代码
    return handleData(response.data)
  },
  error => {
  // 错误信息需要和后端进行协调,然后去配合设置啦
    if(error.response.data.status === 500 && (error.response.data.message === 'token out time'||error.response.data.message==='登录失败或未登录')){
    // 调用登出api
      logonApi.signOut();
      // 存放token到localStorage,这里因为登出,所以设置为空
      setLocalStorage('jwtToken');
      // 跳回登录页
      window.location.href = baseUrl.url1;
    }
    let err = error.response.data.message;
    if (err != '' && err != null && err != undefined) {
    // 错误提醒
      Message({
        type: 'error',
        message: error.response.data.message
      })
      return Promise.reject(error.response.data)
    } else {
      Message({
        type: 'error',
        message: 'HTTP:服务器遇到错误,无法完成请求。'
      })
    }
  })

在这里插入图片描述
很显然,从vscode是看不出它是个啥东西了,让我们看看它是什么妖魔鬼怪!
在这里插入图片描述
有没有发现,它除了包含我们之前的request配置,还多了一个返回的数据。所以我们可以根据它返回的数据来完成自己想要的操作啦。

5.封装成请求

const postFn = (url, data) => {
  return instance
    .post(url, data)
    .catch(handleError)
}

instance是我们之前封装好的axios实例,我们可以通过它调用axios实例方法完成封装。

6.完整代码

由于代码中很多设置是项目要求,所以仅供参考!

代码

import axios from 'axios'
import { baseUrl, pathUrl } from './env'
import Qs from 'qs'
import { Message } from 'element-ui'
import { setLocalStorage,getLocalStorage } from '@/utils/utils'
import logonApi from '../api/logon'

const instance = axios.create({
  // baseURL: baseUrl,
  timeout: 60000,
  headers: {
    'Accept': 'application/json',
    'Content-Type': 'application/json'
  }
})
// http request 请求拦截器
instance.interceptors.request.use(
  config => {
    config.headers.AcceptLanguage = getLocalStorage("locale");
    if (localStorage.jwtToken) {
      config.headers.Authorization = getLocalStorage("jwtToken");
    }
    console.log('config',config);
    return config
  },
  err => {
    return Promise.reject(err)
  }
)
// http response 响应拦截器
instance.interceptors.response.use(
  response => {
    console.log('response',response);
    return handleData(response.data)
  },
  error => {
    if(error.response.data.status===500&&(error.response.data.message==='token out time'||error.response.data.message==='登录失败或未登录')){
      logonApi.signOut();
      // window.location.href = baseUrl.url1;
      setLocalStorage('jwtToken');
      window.location.href = baseUrl.url1;
    }
    let err = error.response.data.message;
    if (err != '' && err != null && err != undefined) {
      Message({
        type: 'error',
        message: error.response.data.message
      })
      return Promise.reject(error.response.data)
    } else {
      Message({
        type: 'error',
        message: 'HTTP:服务器遇到错误,无法完成请求。'
      })
    }
  })
// 生成新的url
function generateUrl (url) {
  const domain = url.domain ? baseUrl[url.domain] : baseUrl['url1'];
  const path = url.path ? pathUrl[url.path] : pathUrl['url1'];
  const newurl = Object.prototype.toString.call(url) === '[object Object]' ? url.url : url;
  return domain + path + newurl
}
// 二次封装方法
const getFn = (url, data) => {
  let newurl = generateUrl(url);
  if (data) {
    newurl += '?'
    for (let i in data) {
      if (data[i] !== '' && data[i] !== null) {
        newurl += i + '=' + data[i] + '&'
      }
    }
    newurl = newurl.toString().substring(0, newurl.length - 1)
  }
  return instance
    .get(newurl)
    .catch(handleError)
}
const postFn = (url, data) => {
  return instance
    .post(generateUrl(url), data)
    .catch(handleError)
}
const deleteFn = (url, data) => {
  return instance
    .delete(generateUrl(url), data)
    .catch(handleError)
}
const postJSON = (url, data) => {
  data = Qs.stringify(data);
  return instance
    .post(generateUrl(url), data)
    .catch(handleError)
}
const patchFn = (url, data) => {
  return instance
    .patch(generateUrl(url), data)
    .catch(handleError)
}
const postFile = (url, data, config) => {
  return instance
    .post(generateUrl(url), data, config)
    .catch(handleError)
}
// 捕获请求错误
function handleError (error) {
  // Promise.reject(error)
  return error
}
// 处理数据
function handleData (data) {
  if (data.hasOwnProperty('ret')) {
    if (data.ret!==null&&data.ret.hasOwnProperty('token')) {
      setLocalStorage('jwtToken',data.ret.token);
    }
  }
  if (data.errcode !== 0){
    Message({
      type: 'error',
      message: data.errmsg
    })
  }
  if(data.errcode === 200 && data.errmsg === "权限鉴定失败"){
    setLocalStorage('jwtToken');
    window.location.href = baseUrl.url1;
  }
  if(data.errcode === 300){ // token超时后 前端处理
    setLocalStorage('jwtToken');
    window.location.href = baseUrl.url1;
  }
  return data
}
export default {
  postFile: postFile,
  postJSON: postJSON,
  post: postFn,
  get: getFn,
  delete: deleteFn,
  patch: patchFn
}

代码中的setLocalStorage和getLocalStorage方法

setLocalStorage

// 设置LocalStorage过期
const setLocalStorage = function  (key, value, days) {
    value = JSON.stringify(value);
    // 设置过期原则
    if (!value) {
      localStorage.removeItem(key)
    } else {
      var Days = days || 24; // 以小时为单位,默认24小时
      var exp = new Date();
      localStorage[key] = JSON.stringify({
        value,
        // 和后端协商做了失效时间
        expires: exp.getTime() + Days * 1000*60*60
      })
    }
}

getLocalStorage

const getLocalStorage = function (name) {
    try {
      let o = JSON.parse(localStorage[name]);
      if (!o || o.expires < Date.now()) {
        return ''
      } else {
        return JSON.parse(o.value)
      }
    } catch (e) {
        // 兼容其他localstorage
      return localStorage[name]
    }
}

总结

封装其实是非常简单的,希望大家都能去手写一遍,这样在以后的项目中就能得心应手的使用啦!


http://www.niftyadmin.cn/n/861681.html

相关文章

防抖节流原理及实现(含演示图)

文章目录前言一、防抖&#xff08;debounce&#xff09;1、什么是防抖&#xff1f;2、防抖实现二、节流&#xff08;throttle&#xff09;1.什么是节流&#xff1f;2.节流实现总结前言 随着前端飞速的发展&#xff0c;用户体验也越来越重要。大家在逛一些网站时&#xff0c;会…

【css定位】超详细!手把手带你体验position属性(含sticky属性与效果图)

文章目录前言一、relative1.介绍2.场景相对自身定位二、absolute1.介绍2.场景相对于除static外的父元素定位父元素都是static相对于谁定位脱离文档流会占位吗三、fixed1.介绍2.场景四、sticky1.介绍2.场景总结前言 面试官&#xff1a;说说position的属性吧。 我&#xff1a;哦…

超超超超详细!手把手带你用js实现简易版position:sticky

文章目录一、基本思路二、实现过程1.准备工作1.获取dom元素&#xff0c;设置偏移量2.给滑动添加事件3.判断是否在可视区4.脱离可视区触发回调函数总结# 前言 前面我们在介绍position属性时&#xff08;不知道的小伙伴可以去看看我的另一篇说position的博客哟&#xff0c;传送门…

一路摸爬滚打,我终于踏上了我的程序员之路!

我正在参与CSDN《新程序员》有奖征文活动&#xff0c;活动链接&#xff1a; https://marketing.csdn.net/p/52c37904f6e1b69dc392234fff425442 文章目录前言浑浑噩噩开学季自信心被重击虚度光阴初识编程你好&#xff0c;前端我的第一个轮播图期末课设前端是没有前途的开始前端之…

$set解决vue中修改数组或对象视图不更新的问题

文章目录前言一、案例二、解决方法$set总结前言 相信大家和我一样&#xff0c;在开发中总是遇到一个问题。 为啥我修改v-for遍历的数组&#xff0c;视图却没有更新&#xff1f;&#xff1f;&#xff1f;当我点击其他操作重新渲染后&#xff0c;又更新了&#xff1f;&#xff…

MongoDB入门学习

文章目录前言一、MongoDB是什么&#xff1f;二、MongoDB的基本操作1.基本指令2.插入文档3.查询文档4.修改文档5.删除文档6.简单操作总结前言 虽说现在关系型数据库还是主流&#xff0c;但是面对某些需求的时候&#xff0c;需要非关系型数据库来补充它&#xff0c;学习一个主流…

使用mongoose在express中操作数据库

文章目录前言一、Mongoose是什么&#xff1f;二、使用步骤1.引入库2.连接数据库3.操作数据库操作前的准备工作增加文档查询文档更新文档删除文档3.将增删查改操作写成接口总结前言 前面我们已经学会怎么去在命令行里操作数据库了&#xff0c;但是我们肯定不能让用户去操作命令…

浅谈xss和csrf攻击

文章目录前言一、XSS是什么&#xff1f;存储型(持久型)反射型(非持久型)dom型二、CSRF是什么&#xff1f;总结前言 由于博主目前在一家主做网络安全的公司实习&#xff0c;之前没有意识到网络安全的严重性&#xff0c;现在才感受到我们的系统存在了这么多问题&#xff0c;很容…