http.js 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  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://feiniaotech-dev.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. // 添加token
  53. const token = uni.getStorageSync('token')
  54. if (token) {
  55. config.header = config.header || {}
  56. config.header.Authorization = `Bearer ${token}`
  57. }
  58. // 记录请求开始时间(用于计算请求耗时)
  59. config.metadata = { startTime: new Date() }
  60. return config
  61. }
  62. this.interceptors.afterResponse = (response) => {
  63. uni.hideLoading()
  64. // 计算请求耗时
  65. const endTime = new Date()
  66. const duration = endTime - response.config.metadata.startTime
  67. console.log(`请求 ${response.config.url} 耗时: ${duration}ms`)
  68. const { data, statusCode } = response
  69. // 根据业务逻辑调整
  70. if (statusCode === 200) {
  71. return data
  72. } else {
  73. return this.handleError(response)
  74. }
  75. }
  76. }
  77. /**
  78. * 错误处理
  79. */
  80. handleError(error) {
  81. let errMsg = '请求失败'
  82. let needLogin = false
  83. if (error.statusCode) {
  84. switch (error.statusCode) {
  85. case 400:
  86. errMsg = error.data?.message || '请求参数错误'
  87. break
  88. case 401:
  89. errMsg = '未授权,请重新登录'
  90. needLogin = true
  91. break
  92. case 403:
  93. errMsg = '拒绝访问'
  94. break
  95. case 404:
  96. errMsg = '请求资源不存在'
  97. break
  98. case 500:
  99. errMsg = '服务器错误'
  100. break
  101. default:
  102. errMsg = `请求错误:${error.statusCode}`
  103. }
  104. } else if (error.errMsg && error.errMsg.includes('timeout')) {
  105. errMsg = '网络请求超时'
  106. } else if (error.errMsg && error.errMsg.includes('network')) {
  107. errMsg = '网络连接失败,请检查网络'
  108. }
  109. // 显示错误提示
  110. uni.showToast({
  111. title: errMsg,
  112. icon: 'none',
  113. duration: 2000
  114. })
  115. // 需要登录的情况
  116. if (needLogin) {
  117. setTimeout(() => {
  118. uni.navigateTo({
  119. url: '/pages/login/login'
  120. })
  121. }, 1500)
  122. }
  123. return Promise.reject(error)
  124. }
  125. /**
  126. * 创建请求实例
  127. */
  128. create() {
  129. const instance = {
  130. request: (options) => {
  131. // 合并配置
  132. let config = { ...this.getDefaultConfig(), ...options }
  133. // 处理URL
  134. if (!config.url.startsWith('http') && !config.url.startsWith('https')) {
  135. config.url = config.baseUrl + config.url
  136. }
  137. // 应用请求拦截
  138. if (typeof this.interceptors.beforeRequest === 'function') {
  139. config = this.interceptors.beforeRequest(config) || config
  140. }
  141. return new Promise((resolve, reject) => {
  142. uni.request({
  143. ...config,
  144. success: (res) => {
  145. // 应用响应拦截
  146. try {
  147. const processed = typeof this.interceptors.afterResponse === 'function'
  148. ? this.interceptors.afterResponse(res)
  149. : res
  150. resolve(processed)
  151. } catch (err) {
  152. reject(this.handleError(err))
  153. }
  154. },
  155. fail: (err) => {
  156. reject(this.handleError(err))
  157. }
  158. })
  159. })
  160. },
  161. // 添加常用方法别名
  162. get: (url, params = {}, options = {}) => {
  163. return this.request({
  164. url,
  165. method: 'GET',
  166. data: params,
  167. ...options
  168. })
  169. },
  170. post: (url, data = {}, options = {}) => {
  171. return this.request({
  172. url,
  173. method: 'POST',
  174. data,
  175. ...options
  176. })
  177. },
  178. put: (url, data = {}, options = {}) => {
  179. return this.request({
  180. url,
  181. method: 'PUT',
  182. data,
  183. ...options
  184. })
  185. },
  186. delete: (url, data = {}, options = {}) => {
  187. return this.request({
  188. url,
  189. method: 'DELETE',
  190. data,
  191. ...options
  192. })
  193. },
  194. upload: (url, filePath, name = 'file', formData = {}, options = {}) => {
  195. return new Promise((resolve, reject) => {
  196. const fullUrl = url.startsWith('http') ? url : BASE_URL + url
  197. const token = uni.getStorageSync('token')
  198. uni.uploadFile({
  199. url: fullUrl,
  200. filePath,
  201. name,
  202. formData,
  203. header: {
  204. 'Authorization': token ? `Bearer ${token}` : '',
  205. ...(options.header || {})
  206. },
  207. success: (res) => {
  208. if (res.statusCode === 200) {
  209. try {
  210. resolve(JSON.parse(res.data))
  211. } catch (e) {
  212. resolve(res.data)
  213. }
  214. } else {
  215. reject(this.handleError(res))
  216. }
  217. },
  218. fail: (err) => {
  219. reject(this.handleError(err))
  220. },
  221. ...options
  222. })
  223. })
  224. }
  225. }
  226. // 初始化拦截器
  227. this.setupInterceptors(instance)
  228. // 绑定this
  229. instance.request = instance.request.bind(this)
  230. instance.get = instance.get.bind(this)
  231. instance.post = instance.post.bind(this)
  232. instance.put = instance.put.bind(this)
  233. instance.delete = instance.delete.bind(this)
  234. instance.upload = instance.upload.bind(this)
  235. return instance
  236. }
  237. }
  238. // 创建单例
  239. const http = new HttpRequest().create()
  240. export default http