interceptors.js 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. import {
  2. http,
  3. toast
  4. } from '@/uni_modules/uview-plus'
  5. import store from '@/store'
  6. import {
  7. DEVE_URL,
  8. PRODUCT_URL
  9. } from '@/common/config.js'
  10. import {
  11. login
  12. } from '../../config/api.js'
  13. import {
  14. Base64
  15. } from 'js-base64'
  16. const CODE_MESSAGE = {
  17. 0: '未可知错误,可能是因为后端不支持跨域CORS、接口地址不存在等问题引起',
  18. 200: '服务器成功返回请求数据',
  19. 201: '新建或修改数据成功',
  20. 202: '一个请求已经进入后台排队(异步任务)',
  21. 204: '删除数据成功',
  22. 400: '发出信息有误',
  23. 401: '用户没有权限(令牌失效、用户名、密码错误、登录过期)',
  24. 402: '令牌过期',
  25. 403: '用户得到授权,但是访问是被禁止的',
  26. 404: '访问资源不存在',
  27. 406: '请求格式不可得',
  28. 410: '请求资源被永久删除,且不会被看到',
  29. 500: '服务器发生错误',
  30. 502: '网关错误',
  31. 503: '服务不可用,服务器暂时过载或维护',
  32. 504: '网关超时',
  33. }
  34. let refreshToking = false
  35. let requests = []
  36. let baseURL = process.env.NODE_ENV === 'development' ? DEVE_URL : PRODUCT_URL
  37. // #ifdef H5
  38. baseURL = ''
  39. // #endif
  40. // 全局配置
  41. http.setConfig((config) => {
  42. config.baseURL = baseURL
  43. return config
  44. })
  45. let loadingTimer = null;
  46. let loadingCount = 0;
  47. const showLoading = () => {
  48. loadingCount++;
  49. if (loadingCount === 1) {
  50. // 延迟显示loading,避免闪烁
  51. loadingTimer = setTimeout(() => {
  52. uni.showLoading({
  53. mask: true
  54. });
  55. }, 300); // 300ms延迟
  56. }
  57. };
  58. const hideLoading = () => {
  59. loadingCount--;
  60. if (loadingCount === 0) {
  61. if (loadingTimer) {
  62. clearTimeout(loadingTimer);
  63. loadingTimer = null;
  64. }
  65. uni.hideLoading();
  66. }
  67. };
  68. const requestInterceptors = (vm) => {
  69. /**
  70. * 请求拦截
  71. */
  72. http.interceptors.request.use((config) => {
  73. config.baseURL = baseURL
  74. // 初始化请求拦截器时,会执行此方法,此时data为undefined,赋予默认{}
  75. config.data = config.data || {}
  76. // 添加token
  77. let token = uni.getStorageSync('access_token')
  78. if (token) config.header['Blade-Auth'] = `Bearer ${token}`
  79. // 添加基础认证
  80. config.header['Authorization'] = `Basic ${Base64.encode('saber:saber_secret')}`
  81. uni.showLoading({
  82. mask: true
  83. })
  84. setTimeout(() => {
  85. uni.hideLoading();
  86. }, 5000)
  87. return config
  88. }, (config) => {
  89. return Promise.reject(config)
  90. })
  91. }
  92. /**
  93. * 刷新令牌
  94. */
  95. const tryRefreshToken = async (config) => {
  96. if (!refreshToking) {
  97. refreshToking = true
  98. try {
  99. const params = {
  100. grantType: 'refresh_token',
  101. refreshToken: uni.getStorageSync('refresh_token')
  102. }
  103. const data = await store.dispatch('refreshToken', params)
  104. if (data.access_token) {
  105. requests.forEach((cb) => cb(data.access_token))
  106. requests = []
  107. return http.request(config)
  108. }
  109. } catch (error) {
  110. console.error('refreshToken error =>', error)
  111. store.commit('userInfo', {})
  112. store.commit('isLogin', false)
  113. store.commit('access_token', '')
  114. store.commit('refresh_token', '')
  115. // 移除自动跳转到登录页面
  116. toast('请登录后操作')
  117. // 添加跳转到登录页面的逻辑
  118. uni.navigateTo({
  119. url: '/packageUser/pages/login/index'
  120. });
  121. return Promise.reject(error)
  122. } finally {
  123. refreshToking = false
  124. }
  125. } else {
  126. return new Promise((resolve) => {
  127. requests.push(() => {
  128. resolve(http.request(config))
  129. })
  130. })
  131. }
  132. }
  133. const responseInterceptors = (vm) => {
  134. /**
  135. * 响应拦截
  136. */
  137. http.interceptors.response.use(async (response) => {
  138. const data = response.data
  139. uni.hideLoading()
  140. // 成功状态判断
  141. if (data.success && data.success == 'true' || data.Code == 0) {
  142. return data
  143. }
  144. // 状态码处理
  145. switch (data.code) {
  146. case 200:
  147. case 201:
  148. return data
  149. case 401:
  150. case 402:
  151. // token过期,尝试刷新
  152. return await tryRefreshToken(response.config)
  153. case 403:
  154. uni.navigateTo({
  155. url: '/pages/error/403'
  156. })
  157. return Promise.reject(data)
  158. case 500:
  159. toast('服务器错误,请稍后重试')
  160. return Promise.reject(data)
  161. default:
  162. // 错误提示
  163. const errMsg = data?.msg || data?.error_description || CODE_MESSAGE[data.code] || '请求失败'
  164. toast(errMsg)
  165. return Promise.reject(data)
  166. }
  167. }, async (error) => {
  168. hideLoading();
  169. uni.hideLoading();
  170. // HTTP状态码处理
  171. switch (error.statusCode) {
  172. case 401:
  173. case 402:
  174. return await tryRefreshToken(error.config)
  175. case 403:
  176. uni.navigateTo({
  177. url: '/pages/error/403'
  178. })
  179. break
  180. case 500:
  181. toast('服务器错误,请稍后重试')
  182. break
  183. default:
  184. toast('网络错误,请检查网络连接')
  185. }
  186. return Promise.reject(error)
  187. })
  188. }
  189. export {
  190. requestInterceptors,
  191. responseInterceptors
  192. }