http.js 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. // utils/http.js
  2. /**
  3. * 环境配置
  4. */
  5. const envConfig = {
  6. development: {
  7. baseUrl: 'https://feiniaotech-dev.sysuimars.cn/'
  8. },
  9. production: {
  10. baseUrl: 'https://birdseye-api.feiniaotech.sysuimars.cn/'
  11. }
  12. }
  13. const currentEnv = process.env.NODE_ENV || 'development'
  14. const BASE_URL = envConfig[currentEnv].baseUrl
  15. /**
  16. * 请求封装类
  17. */
  18. class HttpRequest {
  19. constructor() {
  20. this.queue = {} // 请求队列
  21. this.interceptors = {
  22. beforeRequest: null,
  23. afterResponse: null
  24. }
  25. }
  26. /**
  27. * 获取基础配置
  28. */
  29. getDefaultConfig() {
  30. return {
  31. baseUrl: BASE_URL,
  32. url: '',
  33. header: {
  34. 'Content-Type': 'application/json',
  35. 'X-Requested-With': 'XMLHttpRequest'
  36. },
  37. timeout: 10000,
  38. data: {},
  39. method: 'GET'
  40. }
  41. }
  42. /**
  43. * 设置拦截器
  44. */
  45. setupInterceptors(instance) {
  46. this.interceptors.beforeRequest = (config) => {
  47. // 添加全局loading
  48. uni.showLoading({
  49. title: '加载中',
  50. mask: true
  51. })
  52. config.header.appId = 'wx628f62793fdf5251'
  53. // 添加token
  54. // #ifdef H5
  55. const h5Token = '6288d39b-ed8e-4e67-9dac-796ee30eb5e4'
  56. config.header.token = h5Token
  57. // #endif
  58. // #ifdef MP-WEIXIN
  59. const token = uni.getStorageSync('token')
  60. if (token) {
  61. config.header.token = token
  62. }
  63. // #endif
  64. // 记录请求开始时间(用于计算请求耗时)
  65. config.metadata = { startTime: new Date() }
  66. return config
  67. }
  68. this.interceptors.afterResponse = (response) => {
  69. uni.hideLoading()
  70. const { data, statusCode } = response
  71. if (statusCode === 200) {
  72. return data
  73. } else {
  74. return this.handleError(response)
  75. }
  76. }
  77. }
  78. /**
  79. * 错误处理
  80. */
  81. handleError(error) {
  82. let errMsg = '请求失败'
  83. let needLogin = false
  84. if (error.statusCode) {
  85. switch (error.statusCode) {
  86. case 400:
  87. errMsg = error.data?.message || '请求参数错误'
  88. break
  89. case 401:
  90. errMsg = '未授权,请重新登录'
  91. needLogin = true
  92. break
  93. case 403:
  94. errMsg = '拒绝访问'
  95. break
  96. case 404:
  97. errMsg = '请求资源不存在'
  98. break
  99. case 500:
  100. errMsg = '服务器错误'
  101. break
  102. default:
  103. errMsg = `请求错误:${error.statusCode}`
  104. }
  105. } else if (error.errMsg && error.errMsg.includes('timeout')) {
  106. errMsg = '网络请求超时'
  107. } else if (error.errMsg && error.errMsg.includes('network')) {
  108. errMsg = '网络连接失败,请检查网络'
  109. }
  110. // 显示错误提示
  111. uni.showToast({
  112. title: errMsg,
  113. icon: 'none',
  114. duration: 2000
  115. })
  116. // 需要登录的情况
  117. if (needLogin) {
  118. setTimeout(() => {
  119. uni.navigateTo({
  120. url: '/pages/login/index'
  121. })
  122. }, 1500)
  123. }
  124. return Promise.reject(error)
  125. }
  126. /**
  127. * 创建请求实例
  128. */
  129. create() {
  130. const instance = {
  131. request: (options) => {
  132. // 合并配置
  133. let config = { ...this.getDefaultConfig(), ...options }
  134. // 处理URL
  135. if (!config.url.startsWith('http') && !config.url.startsWith('https')) {
  136. config.url = config.baseUrl + config.url
  137. }
  138. // 应用请求拦截
  139. if (typeof this.interceptors.beforeRequest === 'function') {
  140. config = this.interceptors.beforeRequest(config) || config
  141. }
  142. return new Promise((resolve, reject) => {
  143. uni.request({
  144. ...config,
  145. success: (res) => {
  146. // 应用响应拦截
  147. try {
  148. const processed = typeof this.interceptors.afterResponse === 'function'
  149. ? this.interceptors.afterResponse(res)
  150. : res
  151. resolve(processed)
  152. } catch (err) {
  153. reject(this.handleError(err))
  154. }
  155. },
  156. fail: (err) => {
  157. reject(this.handleError(err))
  158. }
  159. })
  160. })
  161. },
  162. // 添加常用方法别名
  163. get: (url, params = {}, options = {}) => {
  164. return instance.request({
  165. url,
  166. method: 'GET',
  167. data: params,
  168. ...options
  169. })
  170. },
  171. post: (url, data = {}, options = {}) => {
  172. return instance.request({
  173. url,
  174. method: 'POST',
  175. data,
  176. ...options
  177. })
  178. },
  179. put: (url, data = {}, options = {}) => {
  180. return instance.request({
  181. url,
  182. method: 'PUT',
  183. data,
  184. ...options
  185. })
  186. },
  187. delete: (url, data = {}, options = {}) => {
  188. return instance.request({
  189. url,
  190. method: 'DELETE',
  191. data,
  192. ...options
  193. })
  194. },
  195. upload: (url, filePath, name = 'file', formData = {}, options = {}) => {
  196. return new Promise((resolve, reject) => {
  197. const fullUrl = url.startsWith('http') ? url : BASE_URL + url
  198. const token = uni.getStorageSync('token')
  199. uni.uploadFile({
  200. url: fullUrl,
  201. filePath,
  202. name,
  203. formData,
  204. header: {
  205. 'Authorization': token ? `Bearer ${token}` : '',
  206. ...(options.header || {})
  207. },
  208. success: (res) => {
  209. if (res.statusCode === 200) {
  210. try {
  211. resolve(JSON.parse(res.data))
  212. } catch (e) {
  213. resolve(res.data)
  214. }
  215. } else {
  216. reject(this.handleError(res))
  217. }
  218. },
  219. fail: (err) => {
  220. reject(this.handleError(err))
  221. },
  222. ...options
  223. })
  224. })
  225. }
  226. }
  227. // 初始化拦截器
  228. this.setupInterceptors(instance)
  229. // 绑定this
  230. instance.request = instance.request.bind(this)
  231. instance.get = instance.get.bind(this)
  232. instance.post = instance.post.bind(this)
  233. instance.put = instance.put.bind(this)
  234. instance.delete = instance.delete.bind(this)
  235. instance.upload = instance.upload.bind(this)
  236. return instance
  237. }
  238. }
  239. // 创建单例
  240. const http = new HttpRequest().create()
  241. export default http