test-api-client 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,587 @@
1
+ ## **1. 项目概述**
2
+
3
+ 本项目是一个使用 TSUP 作为构建工具,使用TypeScript、Axios 和 Crypto-JS 等技术构建的 ApiClient SDK库,提供了一套完整的客户端解决方案,包括 API 请求处理、sign签名机制、Token 管理、日志记录和错误处理等功能,最终通过npm打包为私有库供客户端使用,包名待确认(api-client、http-client)。
4
+
5
+ ## **2. 功能介绍**
6
+
7
+ ### **2.1 核心功能**
8
+
9
+ | 功能模块 | 描述 |
10
+ | ------------ | ------------------------------------------------------------ |
11
+ | API 请求处理 | 封装了 Axios 库,提供统一的请求接口 |
12
+ | 签名机制 | 自动生成请求签名,确保接口安全性 |
13
+ | Token 管理 | 支持 Token 存储、获取和自动刷新 |
14
+ | 日志记录 | 提供多级别的日志记录功能,支持自定义日志输出 |
15
+ | 业务错误映射 | 基于后端错误码文档实现完整的错误码映射,支持 HTTP 状态码和业务错误码的统一处理 |
16
+ | 错误处理 | 统一的错误类型定义和错误回调机制 |
17
+
18
+ ### **2.2 扩展功能**
19
+
20
+ \- **日志级别控制**:支持 `ALL`、`ERROR`、`FATAL` 、`INFO` 、`TRACE`、`DEBUG`、`WARN`、`OFF` 8个级别的日志控制(采用业界通用的日志标准体系,例如[Sentry](https://docs.sentry.io/platforms/javascript/logs/)/[Log4j](https://logging.apache.org/log4j/2.x/javadoc/log4j-api/org/apache/logging/log4j/Level.html)等通用日志框架)
21
+
22
+ \- **自定义日志****回调**:支持将日志输出到外部系统,可以将格式化后的日志通过事件发送至公司统一的日志管理平台
23
+
24
+ ## **3. 技术选型与分析**
25
+
26
+ ### **3.1 核心技术栈**
27
+
28
+ | 技术/库 | 版本 | 用途 | 选型理由 |
29
+ | ----------------- | ----- | ----------------------- | ------------------------------------------------------------ |
30
+ | TypeScript | 5.4.5 | 开发语言 | 提供类型安全,增强代码可维护性和可读性 |
31
+ | Axios | 1.6.7 | HTTP 客户端 | 成熟稳定,支持浏览器和 Node.js 环境,提供丰富的拦截器功能 |
32
+ | Crypto-JS | 4.2.0 | 加密库 | 用于生成请求签名,支持 MD5 等多种加密算法 |
33
+ | ESLint | 9.3.0 | 代码质量检查 | 提供强大的代码质量检查能力,支持自定义规则,社区生态丰富 |
34
+ | TypeScript ESLint | 8.0.0 | TypeScript 代码检查规则 | 为 TypeScript 设计,与 ESLint 无缝集成,提供针对 TypeScript 语法的专业检查规则 |
35
+ | tsup | 8.0.2 | 构建工具 | 基于 ESBuild,构建速度极快,配置简单,原生支持 TypeScript 和多格式输出 |
36
+
37
+ ## **4. 架构设计**
38
+
39
+ ### **4.1 整体架构**
40
+
41
+ #### **4.1.1 目录结构**
42
+
43
+ ```Plain
44
+ src/
45
+ ├── api/ # API 接口层 - 业务接口封装
46
+ │ └── v1/ # API 版本 v1
47
+ │ ├── airline.ts # 航线相关接口
48
+ │ ├── auth.ts # 认证相关接口
49
+ │ ├── fence.ts # 围栏相关接口
50
+ │ └── index.ts # API 入口文件,导出所有 v1 接口
51
+ ├── client/ # 客户端核心层 - 基础功能实现
52
+ │ ├── error-codes.ts # 错误码映射,包含 HTTP 状态码和业务错误码的映射关系
53
+ │ ├── http.ts # HTTP 请求处理,包含拦截器、请求/响应处理
54
+ │ ├── logger.ts # 日志记录功能,支持多级别日志
55
+ │ ├── sign.ts # 签名生成与验证
56
+ │ ├── state.ts # 状态管理,存储配置等
57
+ │ └── token.ts # Token 存储与管理
58
+ ├── types/ # 类型定义层 - TypeScript 类型定义
59
+ │ └── v1/ # API 版本 v1 类型定义
60
+ │ ├── airline.ts # 航线相关类型
61
+ │ ├── auth.ts # 认证相关类型
62
+ │ ├── fence.ts # 围栏相关类型
63
+ │ └── index.ts # 类型入口文件,导出所有 v1 类型
64
+ ├── index.ts # SDK 主入口,导出所有公开 API
65
+ └── types.ts # 核心类型定义,包含 SDK 配置、错误类型等
66
+ ```
67
+
68
+ ### **4.2 核心流程**
69
+
70
+ #### **4.2.1 API 请求流程**
71
+
72
+ ```mermaid
73
+ sequenceDiagram
74
+ participant App as 应用程序
75
+ participant API as API 方法
76
+ participant Request as requestData 函数
77
+ participant Client as HTTP 客户端
78
+ participant Interceptor as 请求拦截器
79
+ participant Server as 服务器
80
+ participant ResponseInterceptor as 响应拦截器
81
+
82
+ App->>API: 调用 API 方法
83
+ API->>Request: 调用 requestData
84
+ Request->>Client: 获取 HTTP 客户端实例
85
+ Client->>Interceptor: 执行请求
86
+
87
+ Note over Interceptor: 请求拦截器处理流程
88
+ Interceptor->>Interceptor: 1. 生成时间戳和随机 nonce
89
+ Interceptor->>Interceptor: 2. 设置 Token 到请求头
90
+ Interceptor->>Interceptor: 3. 生成请求签名并设置到请求头
91
+
92
+ Interceptor->>Server: 发送 HTTP 请求
93
+ Server-->>ResponseInterceptor: 返回响应
94
+
95
+ Note over ResponseInterceptor: 响应拦截器处理流程
96
+ ResponseInterceptor->>ResponseInterceptor: 1. 记录请求日志
97
+ ResponseInterceptor->>ResponseInterceptor: 2. 检查业务状态码
98
+
99
+ alt 业务状态码正常
100
+ ResponseInterceptor-->>Request: 返回响应数据
101
+ Request-->>API: 返回数据
102
+ API-->>App: 返回数据
103
+ else 业务状态码错误
104
+ ResponseInterceptor->>ResponseInterceptor: 3. 生成 ApiError 并抛出
105
+ ResponseInterceptor-->>Request: 抛出错误
106
+ Request-->>API: 抛出错误
107
+ API-->>App: 抛出错误
108
+ end
109
+
110
+ alt 401 错误 (Token 过期)
111
+ ResponseInterceptor->>ResponseInterceptor: 2. Token 自动刷新
112
+ ResponseInterceptor-->>Request: 重新执行请求
113
+ else 其他 HTTP 错误
114
+ ResponseInterceptor->>ResponseInterceptor: 3. 生成 ApiError 并抛出
115
+ ResponseInterceptor-->>Request: 抛出错误
116
+ Request-->>API: 抛出错误
117
+ API-->>App: 抛出错误
118
+ end
119
+ ```
120
+
121
+ #### **4.2.2 Token 刷新流程**
122
+ ```mermaid
123
+ flowchart TD
124
+ A[检测到 401 错误] --> B{是否正在刷新 Token?}
125
+
126
+ B -->|是| C[将当前请求加入 pending 队列]
127
+ C --> D[等待刷新完成]
128
+
129
+ B -->|否| E[设置 isRefreshing = true]
130
+ E --> F[调用 /auth/v1/refresh 接口]
131
+
132
+ F --> G{刷新成功?}
133
+
134
+ G -->|是| H[更新 Token 存储]
135
+ H --> I[记录 Token 刷新日志]
136
+ I --> J[处理 pending 队列中的请求]
137
+ J --> K[设置 isRefreshing = false]
138
+ K --> L[清空 refreshPromise]
139
+ L --> M[返回新 Token]
140
+
141
+ G -->|否| N[处理 pending 队列中的请求]
142
+ N --> K
143
+ L --> O[抛出错误]
144
+
145
+ D --> M
146
+
147
+ classDef process fill:#cdf,stroke:#333,stroke-width:1px;
148
+ classDef decision fill:#ff9,stroke:#333,stroke-width:1px;
149
+ classDef action fill:#bbf,stroke:#333,stroke-width:1px;
150
+
151
+ class A,C,D,E,F,H,I,J,K,L,M,N,O process;
152
+ class B,G decision;
153
+ ```
154
+
155
+
156
+ ## **5. 核心模块设计与实现**
157
+
158
+ ### **5.1 HTTP 客户端模块 (client/http.ts)**
159
+
160
+ #### **5.1.1 主要功能**
161
+
162
+ - 创建和配置 Axios 实例
163
+ - 请求拦截器:添加签名、Token 等
164
+ - 响应拦截器:处理业务错误、Token 刷新等
165
+ - 提供统一的请求方法
166
+
167
+ #### **5.1.2 核心代码结构**
168
+
169
+ ```TypeScript
170
+ // 创建 HTTP 客户端
171
+ export function createHttpClient(config: ApiClientConfig): AxiosInstance
172
+
173
+ // 初始化 Api 客户端
174
+ export function initApiClient(config: ApiClientConfig): void
175
+
176
+ // 获取 HTTP 客户端实例
177
+ export function getHttpClient(): AxiosInstance
178
+
179
+ // 请求数据
180
+ export async function requestData<TData>(
181
+ cfg: AxiosRequestConfig,
182
+ apiName?: string
183
+ ): Promise<TData>
184
+
185
+ // 刷新 Token
186
+ async function refreshToken(instance: AxiosInstance, config: ApiClientConfig): Promise<string>
187
+ ```
188
+
189
+ ### **5.2 签名模块 (client/sign.ts)**
190
+
191
+ #### **5.2.1 签名算法**
192
+
193
+ 按[对外接口签名方案](https://d78exgr9mw.feishu.cn/wiki/EsJpw0QbkiIIgGk2j9Scux8wnTC?fromScene=spaceOverview)对接口进行加密签名,为保障接口通信安全,所有请求必须进行签名验证。签名基于请求参数、时间戳、随机数和密钥生成,用于验证请求的合法性和完整性。
194
+
195
+ #### **5.2.2 签名生成步骤**
196
+
197
+ 1. **参数收集**:收集 URI、时间戳、nonce、查询参数和请求体
198
+ 2. **参数过滤**:移除 null、undefined 和空字符串值
199
+ 3. **参数排序**:按参数名ASCII 码升序排序
200
+ 4. **拼接签名字符串**:格式为 `key1=value1&key2=value2&secret=secret`
201
+ 5. **加密**:使用 MD5 算法,加盐加密
202
+
203
+ #### **5.2.2 核心代码**
204
+
205
+ ```TypeScript
206
+ function generateSignature(params: Record<string, unknown>, secret: string, salt: string) {
207
+ // 1. 按key排序并拼接字符串
208
+ const sortedKeys = Object.keys(params).sort();
209
+ const paramString = sortedKeys
210
+ .map(key => `${key}=${params[key]}`)
211
+ .join('&') + `&secret=${secret}`;
212
+
213
+ // 2. 转为小写并使用盐值进行MD5
214
+ const strToSign = paramString.toLowerCase();
215
+ const signature = CryptoJS.MD5(strToSign + salt).toString();
216
+
217
+ return signature;
218
+ }
219
+ ```
220
+
221
+ ### **5.3 Token 管理模块 (client/token.ts)**
222
+
223
+ #### **5.3.1 主要功能**
224
+
225
+ - Token 的存储和获取
226
+ - 支持 Token 失效自动刷新重试
227
+
228
+ #### **5.3.2 核心代码**
229
+
230
+ ```TypeScript
231
+ export function setApiToken(token: string | undefined): void
232
+ export function getApiToken(): string | undefined
233
+ ```
234
+
235
+ ### **5.4 日志模块 (client/logger.ts)**
236
+
237
+ #### **5.4.1 主要功能**
238
+
239
+ - 日志级别顺序(TRACE < DEBUG < INFO < WARN < ERROR < FATAL),ALL和OFF是用于配置的特殊级别:
240
+ - ALL:启用所有级别的日志记录
241
+ - TRACE:最详细的日志信息
242
+ - DEBUG:调试信息,有助于诊断问题
243
+ - INFO:程序正常运行时的信息
244
+ - WARN:潜在问题或非预期情况,但系统仍能正常运行
245
+ - ERROR:错误事件影响单个操作,但系统整体仍可用
246
+ - FATAL:导致应用程序完全终止的严重错误
247
+ - OFF: 关闭所有日志记录
248
+ - 日志格式,按照对接ELK、Splunk等主流分析日志系统的实际格式标准(1:JSON格式,2:传统JSON格式):
249
+
250
+ JSON格式:
251
+
252
+ | 字段 | 类型 | 说明 | 示例 |
253
+ | ----------- | ------ | --------------------------------- | ----------------------------- |
254
+ | timestamp | string | ISO 8601 格式时间戳(精确到毫秒) | "2024-04-09T13:36:39.947Z" |
255
+ | level | string | 日志级别(标准值) | "INFO" |
256
+ | module | string | 代码模块(业务逻辑分组) | "api-client" |
257
+ | event | string | 事件类型(业务语义) | "request" |
258
+ | request | object | 请求详情 | 包含 URL、方法、headers、body |
259
+ | response | object | 响应详情 | 包含 status、headers、body |
260
+ | duration_ms | number | 请求耗时(毫秒) | 125 |
261
+ | message | string | 消息描述 | login post /c2/auth/v1/login |
262
+
263
+ ```SQL
264
+ {
265
+ "timestamp": "2026-01-23T02:37:42.257Z",
266
+ "level": "INFO",
267
+ "module": "api-client",
268
+ "event": "request",
269
+ "message": "login post /c2/auth/v1/login",
270
+ "request": {
271
+ "url": "/c2/auth/v1/login",
272
+ "method": "post",
273
+ "headers": {
274
+ "Accept": "application/json, text/plain, */*",
275
+ "Content-Type": "application/json",
276
+ "X-Timestamp": "1769135861970",
277
+ "X-Nonce": "mkq9tbkjdrx989ako2k",
278
+ "X-Sign": "543f1e0e3b4cc16909faf420affd8d09"
279
+ },
280
+ "body": "{\"username\":\"admin\",\"password\":\"admin\"}"
281
+ },
282
+ "response": {
283
+ "status": 200,
284
+ "body": {
285
+ "code": 200,
286
+ "msg": "登录成功",
287
+ "sub_code": 0,
288
+ "sub_msg": "成功",
289
+ "data": {
290
+ "token": "b814b844-a822-4bf2-b920-700cafe05131",
291
+ "expires_in": 1209568,
292
+ "nickName": "管理员",
293
+ "avatar": "admin.png"
294
+ }
295
+ }
296
+ },
297
+ "duration_ms": 286
298
+ }
299
+ ```
300
+
301
+ 2:传统格式
302
+
303
+ 时间戳 [日志级别] [代码模块] [事件类型] [耗时][消息描述]
304
+
305
+ ```Bash
306
+ 2026-01-23T02:40:13.791Z [INFO] [api-client] [request] [duration: 38ms] - login post /c2/auth/v1/login
307
+ Request: post /c2/auth/v1/login
308
+ Headers: {"Accept":"application/json, text/plain, */*","Content-Type":"application/json","X-Timestamp":"1769136013753","X-Nonce":"mkq9wkopau6o8mzns5","X-Sign":"0f161e7138a9be5cf7c36a0d69d7fc71"}
309
+ Body: "{\"username\":\"admin\",\"password\":\"admin\"}"
310
+ Response: 200
311
+ Body: {"code":200,"msg":"登录成功","sub_code":0,"sub_msg":"成功","data":{"token":"2f0173cd-4515-4203-9b34-7438b4fd5f20","expires_in":1209569,"nickName":"管理员","avatar":"admin.png"}}
312
+ ```
313
+
314
+ 目前主流日志系统集成均支持JSON格式,传统格式为预留
315
+
316
+ | 日志系统 | 配置方式 | 解析效果 |
317
+ | ------------ | -------------------- | ----------------------------------------- |
318
+ | ELK Stack | 默认 JSON 解析 | 自动提取 timestamp、level、service 等字段 |
319
+ | Grafana Loki | json 解析器 | 无需配置,直接按字段索引 |
320
+ | Splunk | JSON 解析器 | 字段自动映射到 level、service 等 |
321
+ | 阿里云 SLS | 选择 "JSON" 解析模式 | 字段自动识别,可直接创建索引 |
322
+
323
+ - 日志输出(控制台和自定义回调)
324
+
325
+ #### **5.4.2 核心代码**
326
+
327
+ ```TypeScript
328
+ /**
329
+ * 生成结构化日志
330
+ * @param config - Api客户端配置
331
+ * @param level - 日志级别
332
+ * @param event - 事件类型
333
+ * @param message - 日志消息
334
+ * @param httpLog - HTTP日志结构(可选)
335
+ * @param meta - 其他元数据(可选)
336
+ * @returns 结构化日志对象
337
+ */
338
+ function generateStructuredLog(
339
+ config: ApiClientConfig | undefined,
340
+ level: ApiLogLevel,
341
+ event: string,
342
+ message: string,
343
+ httpLog?: ApiStructuredHttpLog,
344
+ meta?: unknown
345
+ ): ApiStructuredLog {
346
+ const structuredLog: ApiStructuredLog = {
347
+ timestamp: new Date().toISOString(),
348
+ level,
349
+ module: 'api-client',
350
+ event,
351
+ message
352
+ };
353
+
354
+ // 添加HTTP相关信息
355
+ if (httpLog) {
356
+ if (httpLog.url && httpLog.method) {
357
+ structuredLog.request = {
358
+ url: httpLog.url,
359
+ method: httpLog.method,
360
+ headers: httpLog.headers as Record<string, string>,
361
+ body: formatSensitiveData(httpLog.request)
362
+ };
363
+ }
364
+
365
+ if (httpLog.response && typeof httpLog.response === 'object') {
366
+ const responseObj = httpLog.response as any;
367
+ structuredLog.response = {
368
+ status: responseObj.status || responseObj.code || 0,
369
+ body: responseObj
370
+ };
371
+ }
372
+ if (httpLog.durationMs) {
373
+ structuredLog.duration_ms = httpLog.durationMs;
374
+ }
375
+ }
376
+ // 添加其他元数据
377
+ if (meta) {
378
+ Object.assign(structuredLog, meta);
379
+ }
380
+
381
+ return structuredLog;
382
+ }
383
+ ```
384
+
385
+ ### **5.5 状态管理模块 (client/state.ts)**
386
+
387
+ #### **5.5.1 主要功能**
388
+
389
+ - 存储 SDK 配置
390
+ - 存储 Axios 实例
391
+ - 存储 Token
392
+
393
+ #### **5.5.2 核心代码**
394
+
395
+ ```TypeScript
396
+ export interface ApiClientState {
397
+ config?: ApiClientConfig;
398
+ axios?: AxiosInstance;
399
+ token?: string;
400
+ }
401
+ ```
402
+
403
+ ## **6.** **类型定义**
404
+
405
+ ### **6.1 核心类型**
406
+
407
+ #### **6.1.1 ApiClientConfig**
408
+
409
+ ```TypeScript
410
+ export interface ApiClientConfig {
411
+ baseUrl: string; // API 基础 URL
412
+ secret: string; // 密钥
413
+ salt: string; // 加密盐值
414
+ logLevel?: ApiLogLevel; // 日志等级
415
+ logger?: (line: string, level: Exclude<ApiLogLevel, 'all'>, meta?: unknown) => void; // 自定义日志输出
416
+ businessErrorMessageMap?: Record<number, string>; // 业务错误码映射
417
+ tokenRefreshMaxRetries?: number;//Token失效时的最大重试次数,设置为0则一直重试
418
+ }
419
+ ```
420
+
421
+ #### **6.1.2 ApiApiResponse**
422
+
423
+ ```TypeScript
424
+ export interface ApiApiResponse<T> {
425
+ code: number; // 响应状态码
426
+ msg?: string; // 响应消息(短)
427
+ message?: string; // 响应消息(长)
428
+ sub_code?: number; // 子错误码
429
+ sub_msg?: string; // 子错误消息
430
+ data?: T; // 响应数据
431
+ }
432
+ ```
433
+
434
+ ### **6.3 日志级别**
435
+
436
+ ```TypeScript
437
+ export type ApiLogLevel = 'ALL' | 'ERROR' | 'FATAL ' | 'INFO ' | 'TRACE' | 'DEBUG' | 'WARN' | 'OFF
438
+ ```
439
+
440
+ ### 6.4 **错误级别枚举**
441
+
442
+ ```TypeScript
443
+ /**
444
+ * HTTP状态码映射
445
+ */
446
+ export const HTTP_STATUS_MAP: Record<number, string> = {
447
+ 200: '请求成功',
448
+ 400: '参数列表错误',
449
+ 401: '未授权',
450
+ 403: '访问受限,授权过期',
451
+ 404: '资源或服务未找到',
452
+ 405: '不允许的HTTP方法',
453
+ 408: '请求超时',
454
+ 500: '系统内部错误',
455
+ 501: '未实现',
456
+ 503: '服务不可用'
457
+ };
458
+ export enum FunctionModule {
459
+ GENERAL = '00', // 通用/系统
460
+ USER_AUTH = '01', // 用户认证
461
+ SELF_CHECK = '02', // 自检维护
462
+ AIRLINE = '03', // 航线管理
463
+ FENCE = '04', // 电子围栏
464
+ REAL_TIME_DATA = '05', // 实时数据
465
+ VIDEO_STREAM = '06', // 视频流
466
+ AUDIO_STREAM = '07', // 音频流
467
+ MEDIA_SERVICE = '08', // 流媒体服务
468
+ AV_CONTROL = '09', // 音视频控制
469
+ LOG_FILE = '10', // 日志文件
470
+ REMOTE_CONTROL = '11', // 遥控指令
471
+ FLIGHT_STATUS = '12' // 飞行状态
472
+ }
473
+ ```
474
+
475
+ ## **7. API 设计**
476
+
477
+ ### **7.1 初始化 API**
478
+
479
+ ```TypeScript
480
+ export function initApiClient(config: ApiClientConfig): void
481
+ ```
482
+
483
+ ### **7.2 Token 管理 API**
484
+
485
+ ```TypeScript
486
+ export function setApiToken(token: string | undefined): void
487
+ export function getApiToken(): string | undefined
488
+ ```
489
+
490
+ ### **7.3 业务 API**
491
+
492
+ #### **7.3.1 认证相关 API**
493
+
494
+ ```TypeScript
495
+ export function loginApi(params: LoginParams): Promise<LoginResponse>
496
+ export function refreshTokenApi(): Promise<RefreshTokenResponse>
497
+ export function logoutApi(): Promise<LogoutResponse>
498
+ ```
499
+
500
+ #### **7.3.2 航线相关 API**
501
+
502
+ ```TypeScript
503
+ export function airlineAddApi(params: AirlineAddParams): Promise<AirlineAddResponse>
504
+ export function airlineListApi(params: AirlineListParams): Promise<AirlineListResponse>
505
+ export function airlineQueryApi(params: AirlineQueryParams): Promise<AirlineQueryResponse>
506
+ export function airlineUpdateApi(params: AirlineUpdateParams): Promise<AirlineUpdateResponse>
507
+ ```
508
+
509
+ #### **7.3.3 围栏相关 API**
510
+
511
+ ```TypeScript
512
+ export function fenceAddApi(params: FenceAddParams): Promise<FenceAddResponse>
513
+ export function fenceListApi(params: FenceListParams): Promise<FenceListResponse>
514
+ export function fenceQueryApi(params: FenceQueryParams): Promise<FenceQueryResponse>
515
+ export function fenceUpdateApi(params: FenceUpdateParams): Promise<FenceUpdateResponse>
516
+ ```
517
+
518
+ ## **8. 使用方法**
519
+
520
+ ### **8.1 安装**
521
+
522
+ ```Bash
523
+ npm install xxx
524
+ ```
525
+
526
+ ### **8.2 初始化**
527
+
528
+ ```TypeScript
529
+ import { initApiClient, setApiToken } from 'api-client';
530
+
531
+ // 初始化 SDK
532
+ initApiClient({
533
+ baseUrl: 'https://api.example.com',// 基础路径
534
+ secret: 'your-secret',// 密钥
535
+ salt: 'your-salt',// 盐值
536
+ debug: true,// 是否开启调试模式
537
+ logLevel: 'ALL',// 日志级别
538
+ logFormat: 2,// 日志格式
539
+ logOutput: [1,2],// 日志输出
540
+ // 自定义日志记录器
541
+ logger: (log: object | string, level: ApiLogLevel, meta?: unknown) => {
542
+ console.log(log, level, meta)
543
+ },
544
+ // 自定义错误处理
545
+ onError: (error: ApiError) => {
546
+ console.error(error)
547
+ },
548
+ // 自定义业务错误消息映射
549
+ businessErrorMessageMap: {
550
+ 1001: '用户名或密码错误',
551
+ 1002: '验证码过期'
552
+ },
553
+ // 自定义刷新token最大重试次数
554
+ tokenRefreshMaxRetries: 10
555
+ });
556
+
557
+ // 设置初始 Token
558
+ setApiToken('initial-token');
559
+ ```
560
+
561
+ ### **8.3 调用 API**
562
+
563
+ ```TypeScript
564
+ import { loginApi, airlineListApi } from 'xxx';
565
+
566
+ // 登录
567
+ try {
568
+ const loginResult = await loginApi({
569
+ username: 'admin',
570
+ password: 'password'
571
+ });
572
+ console.log('Login success:', loginResult);
573
+ } catch (error) {
574
+ console.error('Login failed:', error);
575
+ }
576
+
577
+ // 获取航线列表
578
+ try {
579
+ const airlines = await airlineListApi({
580
+ page: 1,
581
+ pageSize: 10
582
+ });
583
+ console.log('Airlines:', airlines);
584
+ } catch (error) {
585
+ console.error('Failed to get airlines:', error);
586
+ }
587
+ ```