request.ts 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. /**
  2. * HTTP请求工具类
  3. * 封装uni.request,统一处理请求和响应
  4. */
  5. import { API_CONFIG } from './config';
  6. import { getToken, handleUnauthorized } from './auth';
  7. /**
  8. * 请求配置接口
  9. */
  10. interface RequestConfig {
  11. url: string;
  12. method?: 'GET' | 'POST' | 'PUT' | 'DELETE';
  13. data?: any;
  14. header?: any;
  15. timeout?: number;
  16. /** 是否跳过添加token,用于免登录接口 */
  17. skipAuth?: boolean;
  18. /** 是否静默(不弹 toast),轮询类请求应设为 true */
  19. silent?: boolean;
  20. }
  21. /**
  22. * 响应数据接口
  23. */
  24. interface ResponseData<T = any> {
  25. code: number;
  26. message: string;
  27. data?: T;
  28. }
  29. /**
  30. * 发起HTTP请求
  31. * @param config 请求配置
  32. * @returns Promise<响应数据>
  33. */
  34. export const request = <T = any>(config: RequestConfig): Promise<T> => {
  35. return new Promise((resolve, reject) => {
  36. const { url, method = 'GET', data, header = {}, timeout, skipAuth = false, silent = false } = config;
  37. const effectiveTimeout = timeout ?? (silent ? 5000 : API_CONFIG.timeout);
  38. // 构建完整URL
  39. let fullUrl = url.startsWith('http') ? url : `${API_CONFIG.baseUrl}${url}`;
  40. // 添加token到请求头(skipAuth为true时跳过)
  41. if (!skipAuth) {
  42. const token = getToken();
  43. if (token) {
  44. header['accessToken'] = token;
  45. if (API_CONFIG.enableLog) {
  46. console.log('[请求拦截] 添加token到请求头:', token.substring(0, 8) + '...');
  47. }
  48. } else {
  49. if (API_CONFIG.enableLog) {
  50. console.warn('[请求拦截] 未找到token,请求将不携带token');
  51. }
  52. }
  53. }
  54. // 添加Content-Type
  55. if (!header['Content-Type']) {
  56. header['Content-Type'] = 'application/json';
  57. }
  58. // 打印请求日志
  59. if (API_CONFIG.enableLog && !silent) {
  60. console.log(`[请求] ${method} ${fullUrl}`, data);
  61. }
  62. // 发起请求
  63. uni.request({
  64. url: fullUrl,
  65. method,
  66. data,
  67. header,
  68. timeout: effectiveTimeout,
  69. success: (res: any) => {
  70. // 打印响应日志
  71. if (API_CONFIG.enableLog && !silent) {
  72. console.log(`[响应] ${method} ${fullUrl}`, res.data);
  73. }
  74. const responseData = res.data as ResponseData<T>;
  75. // 处理HTTP状态码
  76. if (res.statusCode !== 200) {
  77. // HTTP 401 同样触发未授权处理
  78. if (res.statusCode === 401) {
  79. handleUnauthorized();
  80. }
  81. const errorMsg = `请求失败: HTTP ${res.statusCode}`;
  82. if (!silent) {
  83. uni.showToast({ title: errorMsg, icon: 'none' });
  84. }
  85. reject(new Error(errorMsg));
  86. return;
  87. }
  88. // 处理业务状态码
  89. if (responseData.code === 200 || responseData.code === 0) {
  90. if (API_CONFIG.enableLog) {
  91. console.log('[响应处理] 业务成功,返回data:', responseData.data);
  92. }
  93. resolve(responseData.data as T);
  94. } else if (responseData.code === 401) {
  95. handleUnauthorized();
  96. const authError = new Error(responseData.message || '未登录');
  97. (authError as any).isAuthError = true;
  98. reject(authError);
  99. } else {
  100. const errorMsg = responseData.message || '操作失败';
  101. if (!silent) {
  102. uni.showToast({ title: errorMsg, icon: 'none' });
  103. }
  104. reject(new Error(errorMsg));
  105. }
  106. },
  107. fail: (err: any) => {
  108. console.error(`[请求失败] ${method} ${fullUrl}`, err);
  109. if (!silent) {
  110. let errorMsg = '网络请求失败';
  111. if (err.errMsg) {
  112. if (err.errMsg.includes('timeout')) {
  113. errorMsg = '请求超时,请检查网络';
  114. } else if (err.errMsg.includes('fail')) {
  115. errorMsg = '网络连接失败,请检查网络';
  116. }
  117. }
  118. uni.showToast({ title: errorMsg, icon: 'none' });
  119. }
  120. reject(new Error(err.errMsg || '网络请求失败'));
  121. }
  122. });
  123. });
  124. };
  125. /**
  126. * GET请求
  127. */
  128. export const get = <T = any>(url: string, data?: any, options?: { skipAuth?: boolean; silent?: boolean }): Promise<T> => {
  129. return request<T>({ url, method: 'GET', data, ...options });
  130. };
  131. /**
  132. * POST请求
  133. */
  134. export const post = <T = any>(url: string, data?: any, options?: { silent?: boolean }): Promise<T> => {
  135. return request<T>({ url, method: 'POST', data, ...options });
  136. };
  137. /**
  138. * PUT请求
  139. */
  140. export const put = <T = any>(url: string, data?: any, options?: { silent?: boolean }): Promise<T> => {
  141. return request<T>({ url, method: 'PUT', data, ...options });
  142. };
  143. /**
  144. * DELETE请求
  145. */
  146. export const del = <T = any>(url: string, data?: any, options?: { silent?: boolean }): Promise<T> => {
  147. return request<T>({ url, method: 'DELETE', data, ...options });
  148. };