http.js 6.2 KB

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