当前位置:   article > 正文

uniapp 微信小程序 封装axios 包含请求拦截、响应拦截、无感刷新令牌功能_uniapp设置axios拦截器

uniapp设置axios拦截器

前言:
1、为什么不适用uniapp自带的请求功能?
答:uniapp自带的请求功能,再刷新了令牌后,重新请求返回的数据无法返回给发起请求的方法。也就是说,刷新令牌后重新发起的请求和第一次发起请求的方法是割裂的。
2、封装文件中,我设置了无感刷新令牌功能。我后台的判断逻辑是,当前端请求的令牌过期时间和当前时间比小于10分钟时,刷新令牌。
 

一、安装axios
1.1、使用HBuilder打开uniapp项目,点击视图->显示终端,打开npm操作页面。
1.2、如果项目中还没有“package.json”文件,请先初始化项目。

npm init -y

1.3、安装axios,建议锁定低版本(使用uniapp-vue3版本时,axios的版本需要0.26.0以下)。

npm i axios@0.26.0

 1.4 在main.js中配置axios

  1. import axios from 'axios'//引入axios
  2. import * as request from '@/common/api/request.js'//自定义请求封装文件
  3. Vue.prototype.$http = request //封装的请求方法
  4. // 解决uniapp 适配axios请求,避免报adapter is not a function错误
  5. // 此配置也可以放在自定义请求封装文件中(例如 request.js)
  6. axios.defaults.adapter = config => {
  7. return new Promise((resolve, reject) => {
  8. let settle = require('axios/lib/core/settle');
  9. let buildURL = require('axios/lib/helpers/buildURL');
  10. uni.request({
  11. method: config.method.toUpperCase(),
  12. url: config.baseURL + buildURL(config.url, config.params, config.paramsSerializer),
  13. header: config.headers,
  14. data: config.data,
  15. dataType: config.dataType,
  16. responseType: config.responseType,
  17. sslVerify: config.sslVerify,
  18. complete: function complete(response) {
  19. response = {
  20. data: response.data,
  21. status: response.statusCode,
  22. errMsg: response.errMsg,
  23. header: response.header,
  24. config: config
  25. };
  26. settle(resolve, reject, response);
  27. }
  28. })
  29. })
  30. }

二、自定义请求封装文件 request.js,我的文件路径是 /根目录/common/api/request.js。

  1. import axios from 'axios' // 引入axios
  2. import store from '@/store/index.js'//引入store仓库
  3. function getToken() { //获取令牌
  4. let token = store.state.accountValue.accessToken //store仓库中的令牌
  5. if (!token) { //令牌不存在,显示登录弹窗
  6. openLoginDialog()
  7. }
  8. return token
  9. }
  10. //令牌过期,刷新令牌请求
  11. function refreshToken() {
  12. return service.get('/account/user/refresh/login').then(res => res)
  13. }
  14. //设置store及微信缓存中的账号信息
  15. function setAccountInfo(accountInfo) {
  16. store.commit('accountValue/SET_ACCOUNT_INFO', accountInfo) //修改store中的账号信息
  17. //存储账号信息到微信缓存中
  18. wx.setStorage({
  19. key: "userInfo",
  20. data: JSON.stringify(accountInfo)
  21. })
  22. }
  23. axios.defaults.headers['Content-Type'] = 'application/json;charset=utf-8'
  24. // 创建axios实例
  25. const baseUrl = store.state.constantValue.hostUrl + store.state.constantValue.port //域名/地址公共前缀
  26. const appid = store.state.constantValue.appid //小程序的appid
  27. const requestTimeout = store.state.constantValue.requestTimeout //默认的请求超时时间,单位毫秒
  28. const service = axios.create({
  29. baseURL: baseUrl, //axios的默认请求地址前缀
  30. timeout: requestTimeout //默认的请求超时时间,单位毫秒
  31. })
  32. let requests = [] // 重试队列数组,把需要刷新令牌的请求都放入这个数组中,每一项将是一个待执行的函数形式
  33. let common = {//默认的请求配置信息
  34. data: {},
  35. header: {
  36. "Content-Type": "application/json",
  37. "Content-Type": "application/x-www-form-urlencoded"
  38. },
  39. method: "GET",
  40. dataType: "json"
  41. }
  42. // 请求拦截器
  43. service.interceptors.request.use(
  44. config => {
  45. // 每次发送请求之前判断vuex中是否存在token
  46. // 如果存在,则统一在http请求的headers都加上token,这样后台根据token判断你的登录情况
  47. // 即使本地存在token,也有可能token是过期的,所以在响应拦截器中要对返回状态进行判断
  48. config.method = config.method || common.method;
  49. if (config.method !== 'GET') {
  50. config.data = config.data || common.data;
  51. }
  52. config.dataType = config.dataType || common.dataType;
  53. config.header = config.header || common.header;
  54. if (config.header.NeedToken === 'NEED') { //如果需要访问令牌
  55. const token = getToken();
  56. !isNull(token) && (config.headers.Authorization = 'Bearer ' + token);
  57. }
  58. return config;
  59. },
  60. error => {
  61. return Promise.error(error);
  62. });
  63. // 响应拦截器
  64. service.interceptors.response.use(
  65. response => {
  66. // 如果返回的状态码为200,说明接口请求成功,可以正常拿到数据
  67. // 否则的话抛出错误
  68. if (response.status === 200) {
  69. let code = response.data.code //code为自定义的后台响应code
  70. if (code === 20009 || code === 20010) { //未登录或者登录异常,需要重新登录时
  71. openLoginDialog()//打开登录弹窗
  72. return Promise.resolve(response.data); //返回响应结果
  73. } else {
  74. if (code === 20017) { //后台要求刷新令牌
  75. const config = response.config
  76. if (!store.state.constantValue.isRefreshing) { //如果正在刷新令牌状态为false
  77. //设置正在刷新令牌状态为true,进入更新令牌阶段
  78. store.commit('constantValue/SET_IS_REFRESHING', true)
  79. //获取刷新令牌请求
  80. return refreshToken().then(res => {
  81. if (res.code === 20000) {
  82. // 刷新令牌成功,设置store及微信缓存中的账号信息
  83. const accountInfo = res.data
  84. setAccountInfo(accountInfo)
  85. //已经刷新了令牌,重新发起重试队列数组中的请求
  86. requests.forEach(cb => cb(accountInfo.accessToken))
  87. // 完成后清空这个数组
  88. requests = []
  89. //重置当前请求的配置,重新发起请求
  90. config.headers.Authorization = 'Bearer ' + accountInfo.accessToken
  91. config.baseURL = baseUrl //axios的默认请求地址前缀
  92. config.timeout = requestTimeout //默认的请求超时时间
  93. return service(config) //重新发起请求,返回的就是当前请求
  94. } else {
  95. openLoginDialog()//打开登录弹窗
  96. }
  97. }).catch(rej => { //令牌刷新发生错误
  98. openLoginDialog()//打开登录弹窗
  99. }).finally(() => {
  100. //完成之后设置正在刷新令牌状态为false
  101. store.commit('constantValue/SET_IS_REFRESHING', false)
  102. })
  103. } else { //如果正在刷新令牌状态为true
  104. if (config.header.NeedToken === 'NEED') { //请求需要令牌
  105. // 返回一个未执行resolve的promise
  106. return new Promise((resolve) => {
  107. // 将resolve放进重试队列数组,用一个函数形式来保存,等令牌刷新后直接执行
  108. requests.push((token) => {
  109. config.headers.Authorization = 'Bearer ' + token
  110. resolve(service(config))
  111. })
  112. })
  113. }
  114. }
  115. }
  116. return Promise.resolve(response.data) //返回响应信息
  117. }
  118. } else { //状态码不为200
  119. return Promise.reject(response.data) //返回响应异常信息
  120. }
  121. },
  122. error => {
  123. return Promise.reject(error) //返回响应错误信息
  124. }
  125. );
  126. export default service;

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小丑西瓜9/article/detail/445176
推荐阅读
相关标签
  

闽ICP备14008679号