request.js 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. let base64 = require('../utils/base64.js').Base64;
  2. import {
  3. http,
  4. toast
  5. } from '@/uni_modules/uview-plus'
  6. import {
  7. DEVE_URL,
  8. PRODUCT_URL
  9. } from '@/common/config.js'
  10. import store from '@/store/index.js'
  11. const CODE_MESSAGE = {
  12. 0: '未可知错误,可能是因为后端不支持跨域CORS、接口地址不存在等问题引起',
  13. 200: '服务器成功返回请求数据',
  14. 201: '新建或修改数据成功',
  15. 202: '一个请求已经进入后台排队(异步任务)',
  16. 204: '删除数据成功',
  17. 400: '发出信息有误',
  18. 401: '用户没有权限(令牌失效、用户名、密码错误、登录过期)',
  19. 402: '令牌过期',
  20. 403: '用户得到授权,但是访问是被禁止的',
  21. 404: '访问资源不存在',
  22. 406: '请求格式不可得',
  23. 410: '请求资源被永久删除,且不会被看到',
  24. 500: '服务器发生错误',
  25. 502: '网关错误',
  26. 503: '服务不可用,服务器暂时过载或维护',
  27. 504: '网关超时',
  28. }
  29. let refreshToking = false
  30. let requests = []
  31. let baseURL = ''
  32. if (process.env.NODE_ENV === 'development') {
  33. baseURL = DEVE_URL
  34. } else {
  35. baseURL = PRODUCT_URL
  36. }
  37. // #ifdef H5
  38. baseURL = ''
  39. // #endif
  40. import {
  41. login
  42. } from '../config/api.js';
  43. import Vue from 'vue'
  44. // 此vm参数为页面的实例,可以通过它引用vuex中的变量
  45. const requestInterceptors = (vm) => {
  46. /**
  47. * axios请求拦截器配置
  48. * @param config
  49. * @returns {any}
  50. */
  51. const requestConf = (config) => {
  52. // 初始化请求拦截器时,会执行此方法,此时data为undefined,赋予默认{}
  53. config.data = config.data || {}
  54. let token = uni.getStorageSync('access_token');
  55. if (token) config.header['Blade-Auth'] = `Bearer ${token}`
  56. // if (token) config.headers['Blade-Auth'] = `Bearer ${token}`
  57. // 根据custom参数中配置的是否需要token,添加对应的请求头
  58. config.header['Authorization'] = `Basic ${base64.encode('saber:saber_secret')}`
  59. // uni.showLoading({
  60. // title: '加载中...',
  61. // mask: true
  62. // })
  63. return config
  64. }
  65. /**
  66. * 刷新刷新令牌
  67. * @param config 过期请求配置
  68. * @returns {any} 返回结果
  69. */
  70. const tryRefreshToken = async (config) => {
  71. if (!refreshToking) {
  72. refreshToking = true
  73. try {
  74. const params = {}
  75. params.grantType = 'refresh_token'
  76. params.refreshToken = uni.getStorageSync('refresh_token')
  77. const data = await store.dispatch('refreshToken', params);
  78. console.log('刷新成功,返回:')
  79. console.log(data)
  80. if (data.access_token) {
  81. requests.forEach((cb) => cb(data.access_token))
  82. requests = []
  83. return uni.$u.http.middleware(requestConf(config))
  84. }
  85. } catch (error) {
  86. console.error('refreshToken error =>', error)
  87. // 使用 store 的 action 处理未登录状态
  88. const pages = getCurrentPages();
  89. const currentPage = pages[pages.length - 1];
  90. const redirectPath = currentPage ? currentPage.route : '';
  91. store.dispatch('handleUnauthorized', redirectPath);
  92. return Promise.reject(error)
  93. } finally {
  94. refreshToking = false
  95. }
  96. } else {
  97. return new Promise((resolve) => {
  98. requests.push(() => {
  99. resolve(uni.$u.http.middleware(requestConf(config)))
  100. })
  101. })
  102. }
  103. }
  104. // 初始化请求配置
  105. uni.$u.http.setConfig((config) => {
  106. /* config 为默认全局配置*/
  107. config.baseURL = baseURL; /* 根域名 */
  108. return config
  109. })
  110. // 请求拦截
  111. uni.$u.http.interceptors.request.use(requestConf, config => { // 可使用async await 做异步操作
  112. return Promise.reject(config)
  113. })
  114. // 响应拦截
  115. uni.$u.http.interceptors.response.use(async (response) => {
  116. uni.hideLoading()
  117. /* 对响应成功做点什么 可使用async await 做异步操作*/
  118. const data = response.data
  119. if (data.success && data.success == 'true' || data.Code == 0) {
  120. return data
  121. }
  122. // 处理未登录和token过期情况
  123. if (data.code === 401 || data.code === 402) {
  124. store.commit('userInfo', {});
  125. store.commit('isLogin', false);
  126. store.commit('access_token', '');
  127. store.commit('refresh_token', '');
  128. // 显示提示
  129. uni.$u.toast(data.code === 401 ? '请先登录' : 'token已过期,请重新登录');
  130. // 获取当前页面路径
  131. const pages = getCurrentPages();
  132. const currentPage = pages[pages.length - 1];
  133. const redirectUrl = currentPage ? encodeURIComponent(currentPage.route) : '';
  134. // 延迟跳转,让用户看到提示
  135. setTimeout(() => {
  136. uni.navigateTo({
  137. url: `/pages/user/login?redirect=/${redirectUrl}`
  138. });
  139. }, 1500);
  140. return Promise.reject(data);
  141. }
  142. // 处理其他状态码
  143. switch (data.code) {
  144. case 200:
  145. case 201:
  146. return data;
  147. case 403:
  148. return vm.$route('/pages/403');
  149. case 500:
  150. uni.$u.toast('服务器响应失败');
  151. return Promise.reject(data);
  152. }
  153. // 其他错误统一提示
  154. const errMsg = data.msg || data.error_description || CODE_MESSAGE[data.code] || '未知错误';
  155. uni.$u.toast(errMsg);
  156. return Promise.reject(data);
  157. }, (error) => {
  158. uni.hideLoading();
  159. // 处理网络错误等
  160. uni.$u.toast('网络请求失败,请检查网络连接');
  161. return Promise.reject(error);
  162. })
  163. }