generator-mico-cli 0.1.24 → 0.1.26
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/generators/micro-react/templates/apps/layout/docs/arch-/350/257/267/346/261/202/346/250/241/345/235/227.md +133 -0
- package/generators/micro-react/templates/apps/layout/src/common/request/types.ts +6 -0
- package/generators/micro-react/templates/apps/layout/src/common/request/url-resolver.ts +37 -3
- package/generators/micro-react/templates/apps/layout/src/components/MicroAppLoader/index.tsx +3 -0
- package/package.json +1 -1
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
# 请求模块架构
|
|
2
|
+
|
|
3
|
+
## 功能概述
|
|
4
|
+
|
|
5
|
+
HTTP 请求层模块化架构,将请求逻辑拆分为 6 个职责单一的模块,遵循 SRP 原则。
|
|
6
|
+
|
|
7
|
+
## 模块结构
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
src/common/request/
|
|
11
|
+
├── index.ts # 模块入口,导出统一 API
|
|
12
|
+
├── types.ts # 类型定义
|
|
13
|
+
├── config.ts # 客户端配置管理
|
|
14
|
+
├── interceptors.ts # 拦截器管理
|
|
15
|
+
├── url-resolver.ts # URL 解析工具
|
|
16
|
+
├── token-refresh.ts # Token 刷新逻辑
|
|
17
|
+
└── sso.ts # SSO 认证逻辑
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## 模块职责
|
|
21
|
+
|
|
22
|
+
| 模块 | 职责 |
|
|
23
|
+
| ------------------ | ----------------------------------------------------- |
|
|
24
|
+
| `types.ts` | 定义 `UnifiedRequestOptions`、`RequestContext` 等接口 |
|
|
25
|
+
| `config.ts` | 管理 API baseUrl、代理前缀、认证端点配置 |
|
|
26
|
+
| `interceptors.ts` | 请求/响应拦截器,Header 构建,401 处理 |
|
|
27
|
+
| `url-resolver.ts` | URL 拼接、代理路径处理、参数移除 |
|
|
28
|
+
| `token-refresh.ts` | Token 过期刷新,请求队列管理 |
|
|
29
|
+
| `sso.ts` | SSO ticket 交换,认证重定向 |
|
|
30
|
+
|
|
31
|
+
## API
|
|
32
|
+
|
|
33
|
+
```typescript
|
|
34
|
+
import { request } from '@/common/request';
|
|
35
|
+
|
|
36
|
+
// 标准请求(开发环境使用相对路径)
|
|
37
|
+
const data = await request<UserInfo>('/api/user');
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## URL 灵活配置
|
|
41
|
+
|
|
42
|
+
`request` 函数支持灵活的 URL 配置选项,满足不同场景需求。
|
|
43
|
+
|
|
44
|
+
### 配置选项
|
|
45
|
+
|
|
46
|
+
| 选项 | 类型 | 默认值 | 说明 |
|
|
47
|
+
|------|------|--------|------|
|
|
48
|
+
| `skipProxy` | `boolean` | `false` | 跳过 proxySuffix 拼接 |
|
|
49
|
+
| `baseURL` | `string` | 全局配置 | 自定义 baseURL,覆盖全局配置 |
|
|
50
|
+
| `rawUrl` | `boolean` | `false` | 使用原始 URL,跳过所有 URL 处理 |
|
|
51
|
+
|
|
52
|
+
### 配置优先级
|
|
53
|
+
|
|
54
|
+
```
|
|
55
|
+
rawUrl: true → 直接返回原始 url
|
|
56
|
+
↓
|
|
57
|
+
绝对 URL → 直接返回
|
|
58
|
+
↓
|
|
59
|
+
开发环境 → 返回相对路径
|
|
60
|
+
↓
|
|
61
|
+
生产环境 → baseURL + (skipProxy ? '' : proxySuffix) + url
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### 使用示例
|
|
65
|
+
|
|
66
|
+
```typescript
|
|
67
|
+
import { request } from '@/common/request';
|
|
68
|
+
|
|
69
|
+
// 1. 默认行为:baseURL + proxySuffix + url
|
|
70
|
+
request('/api/users');
|
|
71
|
+
// 生产环境 => https://api.example.com/proxy-suffix/api/users
|
|
72
|
+
|
|
73
|
+
// 2. 跳过 proxySuffix(直接请求后端,不经过代理)
|
|
74
|
+
request('/api/users', { skipProxy: true });
|
|
75
|
+
// 生产环境 => https://api.example.com/api/users
|
|
76
|
+
|
|
77
|
+
// 3. 自定义 baseURL(请求其他服务)
|
|
78
|
+
request('/api/data', { baseURL: 'https://other-service.com' });
|
|
79
|
+
// 生产环境 => https://other-service.com/proxy-suffix/api/data
|
|
80
|
+
|
|
81
|
+
// 4. 自定义 baseURL + 跳过 proxy(请求第三方 API)
|
|
82
|
+
request('/api/data', {
|
|
83
|
+
baseURL: 'https://third-party.com',
|
|
84
|
+
skipProxy: true
|
|
85
|
+
});
|
|
86
|
+
// 生产环境 => https://third-party.com/api/data
|
|
87
|
+
|
|
88
|
+
// 5. 完全使用原始 URL(微应用场景,URL 已处理好)
|
|
89
|
+
request('/custom/path', { rawUrl: true });
|
|
90
|
+
// 任何环境 => /custom/path(原样返回)
|
|
91
|
+
|
|
92
|
+
// 6. 覆盖默认 proxySuffix
|
|
93
|
+
request('/api/users', { proxySuffix: '/other-proxy' });
|
|
94
|
+
// 生产环境 => https://api.example.com/other-proxy/api/users
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### 典型场景
|
|
98
|
+
|
|
99
|
+
| 场景 | 配置 |
|
|
100
|
+
|------|------|
|
|
101
|
+
| 请求主后端 API | 默认,无需额外配置 |
|
|
102
|
+
| 绕过网关直连后端 | `{ skipProxy: true }` |
|
|
103
|
+
| 请求其他微服务 | `{ baseURL: 'https://xxx' }` |
|
|
104
|
+
| 请求第三方 API | `{ baseURL: 'https://xxx', skipProxy: true }` |
|
|
105
|
+
| 微应用已处理 URL | `{ rawUrl: true }` |
|
|
106
|
+
|
|
107
|
+
## 错误处理
|
|
108
|
+
|
|
109
|
+
错误配置在 `src/requestErrorConfig.ts`,使用类型守卫区分错误类型:
|
|
110
|
+
|
|
111
|
+
```typescript
|
|
112
|
+
// 类型守卫
|
|
113
|
+
const isBizError = (error: unknown): error is BizError => {
|
|
114
|
+
return error instanceof Error && error.name === 'BizError' && 'info' in error;
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
const isAxiosLikeError = (error: unknown): error is AxiosLikeError => {
|
|
118
|
+
return error instanceof Error && ('response' in error || 'request' in error);
|
|
119
|
+
};
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
## 相关文件
|
|
123
|
+
|
|
124
|
+
| 文件 | 说明 |
|
|
125
|
+
| ------------------------------------ | -------------- |
|
|
126
|
+
| `src/requestErrorConfig.ts` | 错误处理配置 |
|
|
127
|
+
| `src/common/auth/cs-auth-manager.ts` | Token 存储管理 |
|
|
128
|
+
|
|
129
|
+
## 注意事项
|
|
130
|
+
|
|
131
|
+
- 外部导入路径不变:`@/common/request`
|
|
132
|
+
- 开发环境使用相对路径,生产环境自动拼接 baseUrl
|
|
133
|
+
- 401 响应自动触发 Token 刷新或 SSO 重定向
|
|
@@ -7,6 +7,12 @@ export type UnifiedRequestOptions = {
|
|
|
7
7
|
proxySuffix?: string;
|
|
8
8
|
useCache?: boolean;
|
|
9
9
|
validateCache?: (url: string, options: UnifiedRequestOptions) => boolean;
|
|
10
|
+
/** 跳过 proxySuffix 拼接 */
|
|
11
|
+
skipProxy?: boolean;
|
|
12
|
+
/** 自定义 baseURL,覆盖全局配置 */
|
|
13
|
+
baseURL?: string;
|
|
14
|
+
/** 使用原始 URL,跳过所有 URL 处理 */
|
|
15
|
+
rawUrl?: boolean;
|
|
10
16
|
[key: string]: unknown;
|
|
11
17
|
};
|
|
12
18
|
|
|
@@ -43,22 +43,56 @@ export const joinProxyAndPath = (proxySuffix: string, path: string): string => {
|
|
|
43
43
|
return `${normalizedProxy}${normalizedPath}`;
|
|
44
44
|
};
|
|
45
45
|
|
|
46
|
+
/**
|
|
47
|
+
* 判断是否为绝对 URL
|
|
48
|
+
*/
|
|
49
|
+
const isAbsoluteUrl = (url: string): boolean => {
|
|
50
|
+
return (
|
|
51
|
+
url.startsWith('http://') ||
|
|
52
|
+
url.startsWith('https://') ||
|
|
53
|
+
url.startsWith('//')
|
|
54
|
+
);
|
|
55
|
+
};
|
|
56
|
+
|
|
46
57
|
/**
|
|
47
58
|
* 解析最终请求 URL
|
|
59
|
+
*
|
|
60
|
+
* 配置优先级:
|
|
61
|
+
* 1. rawUrl: true → 直接返回原始 url
|
|
62
|
+
* 2. 绝对 URL → 直接返回
|
|
63
|
+
* 3. 开发环境 → 返回相对路径
|
|
64
|
+
* 4. 生产环境 → baseURL + (skipProxy ? '' : proxySuffix) + url
|
|
48
65
|
*/
|
|
49
66
|
export const resolveRequestUrl = (
|
|
50
67
|
url: string,
|
|
51
68
|
options?: UnifiedRequestOptions,
|
|
52
69
|
isAlwaysRemote = false,
|
|
53
70
|
): string => {
|
|
54
|
-
|
|
55
|
-
|
|
71
|
+
// rawUrl: 完全透传,不做任何处理
|
|
72
|
+
if (options?.rawUrl) {
|
|
73
|
+
return url;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// 绝对 URL 直接返回
|
|
77
|
+
if (isAbsoluteUrl(url)) {
|
|
78
|
+
return url;
|
|
79
|
+
}
|
|
56
80
|
|
|
81
|
+
const useRelative = process.env.NODE_ENV !== 'production' && !isAlwaysRemote;
|
|
57
82
|
if (useRelative) {
|
|
58
83
|
return url;
|
|
59
84
|
}
|
|
60
85
|
|
|
61
|
-
|
|
86
|
+
// 确定 baseURL
|
|
87
|
+
const baseURL = options?.baseURL ?? resolveApiBaseUrl();
|
|
88
|
+
|
|
89
|
+
// 确定是否拼接 proxySuffix
|
|
90
|
+
const shouldUseProxy = !options?.skipProxy;
|
|
91
|
+
const proxySuffix = shouldUseProxy ? getProxySuffix(options?.proxySuffix) : '';
|
|
92
|
+
|
|
93
|
+
// 拼接最终 URL
|
|
94
|
+
const pathWithProxy = proxySuffix ? joinProxyAndPath(proxySuffix, url) : url;
|
|
95
|
+
return joinBaseUrl(baseURL, pathWithProxy);
|
|
62
96
|
};
|
|
63
97
|
|
|
64
98
|
/**
|
package/generators/micro-react/templates/apps/layout/src/components/MicroAppLoader/index.tsx
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { getAuthInfo } from '@/common/auth/cs-auth-manager';
|
|
2
2
|
import { EEnv, getEnv } from '@/common/env';
|
|
3
|
+
import { request } from '@/common/request';
|
|
3
4
|
import { Spin } from '@arco-design/web-react';
|
|
4
5
|
import { loadMicroApp } from 'qiankun';
|
|
5
6
|
import React, { useEffect, useMemo, useRef, useState } from 'react';
|
|
@@ -68,6 +69,8 @@ const MicroAppLoader: React.FC<MicroAppLoaderProps> = ({
|
|
|
68
69
|
nickname: authInfo.nickname,
|
|
69
70
|
// 传递当前路由路径,让子应用进行内部路由切换
|
|
70
71
|
routePath,
|
|
72
|
+
// 传递主应用的 request 实例,子应用可直接使用
|
|
73
|
+
request,
|
|
71
74
|
};
|
|
72
75
|
};
|
|
73
76
|
|