http.js 6.5 KB

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