register-anti-interceptors.js 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. import qs from 'qs'
  2. import VerifyPoints from './verify-popup'
  3. const verify = new VerifyPoints()
  4. const JSONOrFormData = config => {
  5. let type = ''
  6. const contentType = config.headers['Content-Type']
  7. // json --- application/json;charset=utf-8
  8. // formData --- application/x-www-form-urlencoded
  9. const contentTypeMap = {
  10. json: 'application/json',
  11. formData: 'application/x-www-form-urlencoded'
  12. }
  13. if (!contentType) return 'json'
  14. for (const key in contentTypeMap) {
  15. const matching = contentType.includes(contentTypeMap[key])
  16. if (matching) {
  17. type = key
  18. break
  19. }
  20. }
  21. return type
  22. }
  23. // 缓存原有拦截器
  24. let cacheResponseInterceptors = []
  25. // 缓存所有拦截器,并清除实例上所有拦截器,
  26. function clearAllResponseInterceptors (service) {
  27. // https://github.com/axios/axios/blob/v1.x/lib/core/InterceptorManager.js
  28. // 移除所有拦截器,github中的这个clear函数后来被移除了
  29. const handlers = service.interceptors.response.handlers
  30. if (Array.isArray(handlers) && handlers.length > 0) {
  31. for (let i = 0; i < handlers.length; i++) {
  32. cacheResponseInterceptors.push(handlers[i])
  33. }
  34. service.interceptors.response.handlers = []
  35. }
  36. }
  37. // 从缓存恢复拦截器
  38. function restoreResponseInterceptors (service) {
  39. if (Array.isArray(cacheResponseInterceptors) && cacheResponseInterceptors.length > 0) {
  40. service.interceptors.response.handlers = cacheResponseInterceptors
  41. // 恢复完成后及时清除缓存数组
  42. cacheResponseInterceptors = []
  43. }
  44. }
  45. // 清除所有拦截器,并注册当前拦截器
  46. // 移除拦截器后必须在某处恢复,否则会影响其他请求
  47. function clearOtherResponseInterceptors (service) {
  48. clearAllResponseInterceptors(service)
  49. registerInterceptors(service)
  50. }
  51. function closeVerify () {
  52. if (verify.show) {
  53. verify.verify({ value: false })
  54. }
  55. }
  56. export default function registerInterceptors (service) {
  57. // 注册响应拦截器
  58. service.interceptors.response.use(async (response) => {
  59. const res = response.data
  60. const config = response.config
  61. // 如果请求不是200,有可能是403(被拉黑了),就直接跳过本次拦截
  62. if (response.status !== 200) {
  63. // 如果全局验证码显示,并且返回结果正常。则关闭验证码
  64. closeVerify()
  65. return response
  66. }
  67. // 验证码验证成功
  68. if (res.antiVerify === 1) {
  69. /**
  70. * 思路1(正在使用):移除其他响应拦截器,获取到response并返回后,在恢复拦截器
  71. * 优点:能够完全还原新请求的信息(包含响应头等,兼容验证请求响应头和正常请求响应头不同的情况)
  72. * 缺点:实现稍微复杂
  73. *
  74. * 思路2:仅替换response中请求返回的数据。不操作任何拦截器,await service(conf)后,直接替换response中的data即可
  75. * 优点:实现简单
  76. * 缺点:不能实现<思路1>中完全复现响应头的情况
  77. */
  78. // 移除其他响应拦截器
  79. clearOtherResponseInterceptors(service)
  80. let r = response
  81. try {
  82. r = await service(config)
  83. // 恢复响应拦截
  84. restoreResponseInterceptors(service)
  85. } catch (error) {
  86. // 恢复响应拦截
  87. restoreResponseInterceptors(service)
  88. console.error(error)
  89. } finally {
  90. closeVerify()
  91. }
  92. return r
  93. } else {
  94. restoreResponseInterceptors(service)
  95. }
  96. // 需要验证
  97. if (res.antiVerify === -1 && res.textVerify) {
  98. // 等待验证码操作完成
  99. const iReceivedMsg = await new Promise((resolve) => {
  100. verify.verify({
  101. value: true,
  102. imgBase64: res.imgData,
  103. textVerify: res.textVerify,
  104. refresh () {
  105. resolve({
  106. type: 'refresh'
  107. })
  108. },
  109. confirm (msg) {
  110. resolve({
  111. type: 'confirm',
  112. imgw: msg.imgWidth,
  113. antiVerifyCheck: msg.pointsCoordinate.join(';')
  114. })
  115. }
  116. })
  117. })
  118. // 如果确定事件触发
  119. if (iReceivedMsg && iReceivedMsg.type === 'confirm') {
  120. // GET请求在data中添加数据, POST请求在params中添加数据
  121. const requestType = config.method.toUpperCase()
  122. switch (requestType) {
  123. case 'GET': {
  124. if (config.params) {
  125. config.params.imgw = iReceivedMsg.imgw
  126. config.params.antiVerifyCheck = iReceivedMsg.antiVerifyCheck
  127. } else {
  128. config.params = iReceivedMsg
  129. }
  130. break
  131. }
  132. case 'POST': {
  133. // 判断json还是formData
  134. const sendVerify = {
  135. imgw: iReceivedMsg.imgw,
  136. antiVerifyCheck: iReceivedMsg.antiVerifyCheck
  137. }
  138. const sendType = JSONOrFormData(config)
  139. if (sendType === 'formData') {
  140. if (config.data) {
  141. // 先把字符串转为对象,赋值后在转回字符串
  142. const cacheMsg = qs.parse(config.data)
  143. config.data = qs.stringify({
  144. ...cacheMsg,
  145. ...sendVerify
  146. })
  147. } else {
  148. config.data = qs.stringify(sendVerify)
  149. }
  150. } else if (sendType === 'json') {
  151. if (config.data) {
  152. // 先把字符串转为对象,赋值后在转回字符串
  153. config.data = JSON.parse(config.data)
  154. Object.assign(config.data, sendVerify)
  155. config.data = JSON.stringify(config.data)
  156. } else {
  157. config.data = JSON.stringify(sendVerify)
  158. }
  159. }
  160. break
  161. }
  162. default: {
  163. console.log('非常规请求,请单独配置拦截请求内容,并写入参数 --- 来自: @jianyu/vue-anti')
  164. break
  165. }
  166. }
  167. }
  168. // 重发请求以验证《验证码》是否正确
  169. // 此时不需要当前拦截器以外的拦截器
  170. // 移除其他响应拦截器,在请求时恢复
  171. clearOtherResponseInterceptors(service)
  172. return service(config)
  173. } else {
  174. return response
  175. }
  176. }, error => {
  177. return error
  178. })
  179. }