request.js 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. // 统一的请求发送
  2. import axios from 'axios'
  3. import qs from 'qs'
  4. import { Modal, message, notification } from 'ant-design-vue'
  5. import sysConfig from '@/config/index'
  6. import tool from '@/utils/tool'
  7. // 以下这些code需要重新登录
  8. const reloadCodes = [401, 1011007, 1011008]
  9. const errorCodeMap = {
  10. 400: '发出的请求有错误,服务器没有进行新建或修改数据的操作。',
  11. 401: '用户没有权限(令牌、用户名、密码错误)。',
  12. 403: '用户得到授权,但是访问是被禁止的。',
  13. 404: '发出的请求针对的是不存在的记录,服务器没有进行操作。',
  14. 406: '请求的格式不可得。',
  15. 410: '请求的资源被永久删除,且不会再得到的。',
  16. 422: '当创建一个对象时,发生一个验证错误。',
  17. 500: '服务器发生错误,请检查服务器。',
  18. 502: '网关错误。',
  19. 503: '服务不可用,服务器暂时过载或维护。',
  20. 504: '网关超时。'
  21. }
  22. // 定义一个重新登录弹出窗的变量
  23. const loginBack = ref(false)
  24. // 创建 axios 实例
  25. const service = axios.create({
  26. baseURL: '/api', // api base_url
  27. timeout: sysConfig.TIMEOUT // 请求超时时间
  28. })
  29. const whiteList = ['footprint/add', 'coursestudentburialpoint/add', 'coursecentry/addViewCount','courselog/add','userread/add']
  30. function urlStr(str) {
  31. const last = str.lastIndexOf('/')
  32. const secondLast = str.lastIndexOf('/', last - 1)
  33. return str.substring(secondLast + 1)
  34. }
  35. // HTTP request 拦截器
  36. service.interceptors.request.use(
  37. (config) => {
  38. const token = tool.data.get('TOKEN')
  39. if (token) {
  40. config.headers[sysConfig.TOKEN_NAME] = sysConfig.TOKEN_PREFIX + token
  41. }
  42. if (!sysConfig.REQUEST_CACHE && config.method === 'get') {
  43. config.params = config.params || {}
  44. config.params._ = new Date().getTime()
  45. }
  46. Object.assign(config.headers, sysConfig.HEADERS)
  47. return config
  48. },
  49. (error) => {
  50. return Promise.reject(error)
  51. }
  52. )
  53. // 保持重新登录Modal的唯一性
  54. const error = () => {
  55. loginBack.value = true
  56. Modal.error({
  57. title: '提示:',
  58. okText: '重新登录',
  59. content: '登录已失效, 请重新登录',
  60. onOk: () => {
  61. loginBack.value = false
  62. tool.data.remove('TOKEN')
  63. tool.data.remove('USER_INFO')
  64. tool.data.remove('MENU')
  65. tool.data.remove('PERMISSIONS')
  66. window.location.reload()
  67. }
  68. })
  69. }
  70. // HTTP response 拦截器
  71. service.interceptors.response.use(
  72. (response) => {
  73. // 配置了blob,不处理直接返回文件流
  74. if (response.config.responseType === 'blob') {
  75. if (response.status === 200) {
  76. return response
  77. } else {
  78. message.warning('文件下载失败或此文件不存在')
  79. return
  80. }
  81. }
  82. const data = response.data
  83. const code = data.code
  84. if (reloadCodes.includes(code)) {
  85. if (!loginBack.value) {
  86. error()
  87. }
  88. return
  89. }
  90. if (code !== 200) {
  91. const customErrorMessage = response.config.customErrorMessage
  92. message.error(customErrorMessage || data.msg)
  93. return Promise.reject(data)
  94. // 自定义错误提示,覆盖后端返回的message
  95. // 使用示例:
  96. // export function customerList (data) {
  97. // return request('list', data, 'get', {
  98. // customErrorMessage: '自定义错误消息提示'
  99. // });
  100. // }
  101. } else {
  102. // 统一成功提示
  103. const responseUrl = response.config.url
  104. const apiNameArray = [
  105. 'add',
  106. 'edit',
  107. 'delete',
  108. 'update',
  109. 'grant',
  110. 'reset',
  111. 'stop',
  112. 'pass',
  113. 'disable',
  114. 'enable',
  115. 'revoke',
  116. 'suspend',
  117. 'active',
  118. 'turn',
  119. 'adjust',
  120. 'reject',
  121. 'saveDraft'
  122. ]
  123. apiNameArray.forEach((apiName) => {
  124. if (!whiteList.includes(urlStr(responseUrl))) {
  125. if (responseUrl.includes(apiName)) {
  126. message.success(data.msg)
  127. }
  128. }
  129. })
  130. }
  131. return Promise.resolve(data.data)
  132. },
  133. (error) => {
  134. if (error) {
  135. const status = 503
  136. const description = errorCodeMap[status]
  137. notification.error({
  138. message: '请求错误',
  139. description
  140. })
  141. return Promise.reject(status)
  142. }
  143. }
  144. )
  145. // 适配器, 用于适配不同的请求方式
  146. export const baseRequest = (url, value = {}, method = 'post', options = {}) => {
  147. url = sysConfig.API_URL + url
  148. if (method === 'post') {
  149. return service.post(url, value, options)
  150. } else if (method === 'get') {
  151. return service.get(url, { params: value, ...options })
  152. } else if (method === 'formdata') {
  153. // form-data表单提交的方式
  154. return service.post(url, qs.stringify(value), {
  155. headers: {
  156. 'Content-Type': 'multipart/form-data'
  157. },
  158. ...options
  159. })
  160. } else {
  161. // 其他请求方式,例如:put、delete
  162. return service({
  163. method: method,
  164. url: url,
  165. data: value,
  166. ...options
  167. })
  168. }
  169. }
  170. // 模块内的请求, 会自动加上模块的前缀
  171. export const moduleRequest =
  172. (moduleUrl) =>
  173. (url, ...arg) => {
  174. return baseRequest(moduleUrl + url, ...arg)
  175. }
  176. export default service