Files
leaudit-platform-frontend/docs/RBAC路由权限集成_修复说明.md
T
2025-12-05 00:09:32 +08:00

311 lines
7.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# RBAC 路由权限集成 - 修复说明
## 🐛 问题描述
在集成 RBAC 路由权限时遇到以下错误:
```
TypeError: endpoint.startsWith is not a function
at buildUrl (axios-client.ts:168:16)
at apiRequest (axios-client.ts:275:17)
```
---
## 🔍 问题原因
### 1. `apiRequest` 调用方式错误
**错误代码**
```typescript
const response = await apiRequest<BackendRoutesResponse>({
method: 'GET',
url: '/rbac/user/routes', // ❌ 错误:将对象作为第一个参数
headers: {
'Authorization': `Bearer ${jwt}`
}
});
```
**问题**
- `apiRequest` 函数的第一个参数应该是 `endpoint` 字符串
- 我却传递了一个包含 `method``url``headers` 的对象
- 导致 `buildUrl` 函数接收到对象而不是字符串,调用 `endpoint.startsWith` 时报错
---
### 2. 响应数据访问方式错误
**`apiRequest` 函数签名**
```typescript
export async function apiRequest<T>(
endpoint: string, // 第一个参数:端点路径
options: ExtendedAxiosRequestConfig, // 第二个参数:配置对象
params?: QueryParams // 第三个参数:查询参数(可选)
): Promise<ApiResponse<T>>
```
**返回值类型**
```typescript
type ApiResponse<T> = {
data?: T; // 后端返回的完整响应对象
error?: string; // 错误信息
status: number; // HTTP 状态码
headers?: Record<string, string>;
};
```
**后端返回格式**
```json
{
"code": 0,
"msg": "成功",
"data": {
"user_id": 5,
"username": "admin",
"routes": [...]
}
}
```
**数据访问层级**
```typescript
response.data // 整个后端响应对象 { code, msg, data }
response.data.code // 业务状态码
response.data.msg // 提示信息
response.data.data // 实际数据 { user_id, username, routes }
response.data.data.routes // 路由数组
```
---
## ✅ 修复方案
### 修复 1:正确调用 `apiRequest`
**修复后代码**
```typescript
const response = await apiRequest<BackendRoutesResponse>(
'/rbac/user/routes', // ✅ 第一个参数:endpoint 字符串
{
method: 'GET',
headers: {
'Authorization': `Bearer ${jwt}`
}
} // ✅ 第二个参数:配置对象
);
```
**关键点**
- 第一个参数:端点路径字符串(如 `'/rbac/user/routes'`
- 第二个参数:配置对象(包含 method、headers 等)
- 第三个参数:查询参数对象(可选)
---
### 修复 2:正确访问响应数据
**修复后代码**
```typescript
// 检查响应是否成功
if (response.error) {
console.error('❌ [User Routes] API 请求失败:', response.error);
return { success: false, error: response.error };
}
// 检查响应数据
if (!response.data) {
console.error('❌ [User Routes] 后端未返回数据');
return { success: false, error: "后端未返回数据" };
}
const backendResponse = response.data; // 整个后端响应对象
// 检查业务状态码
if (backendResponse.code !== 0 && backendResponse.code !== 200) {
console.error(`❌ [User Routes] 后端返回错误: ${backendResponse.msg}`);
return { success: false, error: backendResponse.msg };
}
// 访问实际数据
const routes = backendResponse.data.routes; // 路由数组
```
**关键点**
- `response.data` → 后端返回的完整对象(包含 code、msg、data
- `backendResponse.code` → 业务状态码(0 或 200 表示成功)
- `backendResponse.data.routes` → 路由数组
---
## 📊 数据流图
```
apiRequest<BackendRoutesResponse>(endpoint, options)
axios.request(config)
后端响应 (HTTP 200)
response.data = {
code: 0,
msg: "成功",
data: {
user_id: 5,
username: "admin",
routes: [...]
}
}
ApiResponse<BackendRoutesResponse> = {
data: { ← response.data 就是整个后端响应
code: 0,
msg: "成功",
data: {
user_id: 5,
username: "admin",
routes: [...]
}
},
status: 200,
headers: {...}
}
```
---
## 🧪 测试验证
### 1. 清除缓存
```javascript
localStorage.clear()
location.reload()
```
### 2. 重新登录
使用测试账号登录(如 `000 / admin06111`
### 3. 观察控制台日志
**预期输出**
```
🔍 [User Routes] 获取用户路由,角色: admin
🔍 [User Routes] 后端返回: { data: { code: 0, msg: "成功", ... }, status: 200 }
✅ [User Routes] 成功获取 29 个路由
📋 [User Routes] 菜单数据: [...]
✅ [Sidebar] 用户路由权限加载成功: [...]
```
**如果仍然报错**,检查:
1. 后端接口 `/rbac/user/routes` 是否正常运行
2. JWT token 是否有效
3. 后端返回的数据格式是否正确
---
## 📁 修改的文件
### `app/api/auth/user-routes.ts`
**修改位置**`getUserRoutesByRole` 函数
**修改内容**
1. 修正 `apiRequest` 调用方式(第一个参数是 endpoint 字符串)
2. 修正响应数据访问方式(通过 `response.data.data.routes` 访问路由数组)
**Git Diff**
```diff
- const response = await apiRequest<BackendRoutesResponse>({
- method: 'GET',
- url: '/rbac/user/routes',
- headers: { 'Authorization': `Bearer ${jwt}` }
- });
+ const response = await apiRequest<BackendRoutesResponse>(
+ '/rbac/user/routes', // endpoint (第一个参数)
+ {
+ method: 'GET',
+ headers: { 'Authorization': `Bearer ${jwt}` }
+ } // options (第二个参数)
+ );
- if (response.code !== 0 && response.code !== 200) {
- // ...
- }
+ const backendResponse = response.data;
+ if (backendResponse.code !== 0 && backendResponse.code !== 200) {
+ // ...
+ }
- const routes = response.data.routes;
+ const routes = backendResponse.data.routes;
```
---
## 💡 经验总结
### 1. 仔细检查函数签名
在调用函数之前,务必确认:
- 参数的数量和顺序
- 每个参数的类型
- 返回值的结构
### 2. 理解数据嵌套结构
后端返回的数据通常有多层嵌套,需要逐层访问:
```
response (ApiResponse)
└─ data (后端完整响应)
├─ code (业务状态码)
├─ msg (提示信息)
└─ data (实际数据)
└─ routes (路由数组)
```
### 3. 使用 TypeScript 类型检查
如果正确定义了类型,TypeScript 会在编译时发现这类错误:
```typescript
// 如果这样调用,TypeScript 应该报错
apiRequest<BackendRoutesResponse>({
method: 'GET',
url: '/rbac/user/routes'
});
// ❌ Argument of type '{ method: string; url: string; }' is not assignable to parameter of type 'string'
```
### 4. 添加详细的调试日志
在关键步骤添加日志,方便定位问题:
```typescript
console.log('🔍 [User Routes] 后端返回:', response);
console.log('📋 [User Routes] 路由数组:', routes);
```
---
## ⚠️ 注意事项
1. **axios 拦截器会自动添加 Authorization 头**
- 从 localStorage 读取 `access_token`
- 但为了确保使用正确的 token,这里仍然显式传递
2. **后端接口必须返回标准格式**
- `code`: 业务状态码(0 或 200 表示成功)
- `msg`: 提示信息
- `data`: 实际数据(包含 `routes` 数组)
3. **Element UI 图标映射**
- 后端返回的是 Element UI 图标(如 `el-icon-s-home`
- 前端会自动转换为 RemixIcon(如 `ri-home-line`
---
**修复完成时间**: 2025-11-17
**修复者**: Claude Code