http.ts 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. // HTTP 请求封装
  2. import { router } from 'expo-router';
  3. import { COMMON_HEADER, SERVICE_URL } from './config';
  4. export const SUCCESS_CODE = 0;
  5. export const AUTH_INVALID = 401;
  6. export const AUTH_INVALID_2 = 403;
  7. interface RequestOptions {
  8. loading?: boolean;
  9. showMsg?: boolean;
  10. method?: 'GET' | 'POST';
  11. token?: string;
  12. }
  13. interface ApiResponse<T = any> {
  14. code: number;
  15. msg: string;
  16. data: T;
  17. success: boolean;
  18. count?: number;
  19. }
  20. // 存储 token
  21. let authToken: string | null = null;
  22. export const setToken = (token: string | null) => {
  23. authToken = token;
  24. };
  25. export const getToken = () => authToken;
  26. // 处理认证失败
  27. const handleAuthError = () => {
  28. setToken(null);
  29. // 跳转到登录页
  30. router.push('/login');
  31. };
  32. // 基础请求方法
  33. export const request = async <T = any>(
  34. url: string,
  35. data: any = {},
  36. options: RequestOptions = {}
  37. ): Promise<ApiResponse<T>> => {
  38. const { method = 'POST' } = options;
  39. const headers: Record<string, string> = {
  40. 'Content-Type': 'application/json',
  41. track: JSON.stringify(COMMON_HEADER),
  42. };
  43. if (authToken) {
  44. headers.Authentication = authToken;
  45. }
  46. const fullUrl = url.startsWith('http') ? url : `${SERVICE_URL}${url}`;
  47. try {
  48. const config: RequestInit = {
  49. method,
  50. headers,
  51. };
  52. if (method === 'GET') {
  53. const params = new URLSearchParams();
  54. Object.keys(data).forEach((key) => {
  55. if (data[key] !== undefined && data[key] !== null) {
  56. params.append(key, String(data[key]));
  57. }
  58. });
  59. const queryString = params.toString();
  60. const requestUrl = queryString ? `${fullUrl}?${queryString}` : fullUrl;
  61. const response = await fetch(requestUrl, config);
  62. const result = await response.json();
  63. // 处理 401/403 认证失败
  64. if (result.code === AUTH_INVALID || result.code === AUTH_INVALID_2) {
  65. handleAuthError();
  66. return {
  67. code: result.code,
  68. msg: '登录已过期,请重新登录',
  69. data: null as any,
  70. success: false,
  71. };
  72. }
  73. return {
  74. ...result,
  75. success: result.code == SUCCESS_CODE, // 使用 == 兼容字符串 "0" 和数字 0
  76. };
  77. } else {
  78. config.body = JSON.stringify(data);
  79. const response = await fetch(fullUrl, config);
  80. const result = await response.json();
  81. // 处理 401/403 认证失败
  82. if (result.code === AUTH_INVALID || result.code === AUTH_INVALID_2) {
  83. handleAuthError();
  84. return {
  85. code: result.code,
  86. msg: '登录已过期,请重新登录',
  87. data: null as any,
  88. success: false,
  89. };
  90. }
  91. return {
  92. ...result,
  93. success: result.code == SUCCESS_CODE, // 使用 == 兼容字符串 "0" 和数字 0
  94. };
  95. }
  96. } catch (error) {
  97. console.error('Request error:', error);
  98. return {
  99. code: -1,
  100. msg: '网络异常',
  101. data: null as any,
  102. success: false,
  103. };
  104. }
  105. };
  106. // GET 请求
  107. export const get = <T = any>(url: string, params: any = {}, options: RequestOptions = {}) => {
  108. return request<T>(url, params, { ...options, method: 'GET' });
  109. };
  110. // POST 请求
  111. export const post = <T = any>(url: string, data: any = {}, options: RequestOptions = {}) => {
  112. return request<T>(url, data, { ...options, method: 'POST' });
  113. };
  114. // 带 loading 的 GET 请求
  115. export const getL = <T = any>(url: string, params: any = {}, options: RequestOptions = {}) => {
  116. return get<T>(url, params, { ...options, loading: true });
  117. };
  118. // 带 loading 的 POST 请求
  119. export const postL = <T = any>(url: string, data: any = {}, options: RequestOptions = {}) => {
  120. return post<T>(url, data, { ...options, loading: true });
  121. };