296 lines
7.7 KiB
Markdown
296 lines
7.7 KiB
Markdown
# 游客模式问题最终诊断 - 2026-02-01
|
||
|
||
## 问题现状
|
||
|
||
游客模式下,以下三个页面仍然无法显示数据:
|
||
1. 选择陪伴员页面 (`/api/teacher/list`)
|
||
2. 兴趣培养页面 (`/api/interest-course/list`)
|
||
3. 专项突破页面 (`/api/special-course/list`)
|
||
|
||
## 后端代码检查结果
|
||
|
||
### ✅ TeacherController.java
|
||
|
||
**接口**: `GET /api/teacher/list`
|
||
|
||
**代码分析**:
|
||
```java
|
||
@GetMapping("/list")
|
||
public Result<Page<TeacherVO>> getTeacherList(
|
||
@RequestParam(required = false) String keyword,
|
||
@RequestParam(required = false) String teacherName,
|
||
// ... 其他参数
|
||
@RequestParam(defaultValue = "1") Integer page,
|
||
@RequestParam(defaultValue = "10") Integer size) {
|
||
// ✅ 没有使用 userId 参数
|
||
// ✅ 没有从 HttpServletRequest 获取 userId
|
||
// ✅ 直接调用 Service 查询数据
|
||
Page<Teacher> result = teacherService.getTeacherList(...);
|
||
return Result.success((Page) result);
|
||
}
|
||
```
|
||
|
||
**结论**: ✅ 这个接口**不需要登录**,应该可以正常返回数据
|
||
|
||
### ✅ InterestCourseController.java
|
||
|
||
**接口**: `GET /api/interest-course/list`
|
||
|
||
**代码分析**:
|
||
```java
|
||
@GetMapping("/list")
|
||
public Result<Page<InterestCourse>> getCourseList(
|
||
@RequestParam(defaultValue = "1") Integer pageNum,
|
||
@RequestParam(defaultValue = "10") Integer pageSize,
|
||
@RequestParam(required = false) String keyword,
|
||
@RequestParam(required = false) String category) {
|
||
// ✅ 没有使用 userId 参数
|
||
// ✅ 没有从 HttpServletRequest 获取 userId
|
||
// ✅ 直接调用 Service 查询数据
|
||
Page<InterestCourse> page = interestCourseService.getCourseList(...);
|
||
return Result.success(page);
|
||
}
|
||
```
|
||
|
||
**结论**: ✅ 这个接口**不需要登录**,应该可以正常返回数据
|
||
|
||
### ✅ SpecialCourseController.java
|
||
|
||
**接口**: `GET /api/special-course/list`
|
||
|
||
**代码分析**:
|
||
```java
|
||
@GetMapping("/list")
|
||
public Result<List<SpecialCourse>> getCourseList(
|
||
@RequestParam(required = false) String category,
|
||
@RequestParam(required = false) String subCategory,
|
||
// ... 其他参数
|
||
@RequestParam(required = false) String sortBy) {
|
||
// ✅ 没有使用 userId 参数
|
||
// ✅ 没有从 HttpServletRequest 获取 userId
|
||
// ✅ 直接调用 Service 查询数据
|
||
List<SpecialCourse> list = specialCourseService.list(wrapper);
|
||
return Result.success(list);
|
||
}
|
||
```
|
||
|
||
**结论**: ✅ 这个接口**不需要登录**,应该可以正常返回数据
|
||
|
||
## JWT拦截器检查
|
||
|
||
**文件**: `JwtInterceptor.java`
|
||
|
||
**当前逻辑**:
|
||
```java
|
||
// ✅ 如果没有token,不抛出异常,直接放行
|
||
if (!StringUtils.hasText(token)) {
|
||
System.out.println("token为空,放行请求");
|
||
return true;
|
||
}
|
||
```
|
||
|
||
**结论**: ✅ JWT拦截器已经修改为放行无token请求
|
||
|
||
## WebMvcConfig检查
|
||
|
||
**文件**: `WebMvcConfig.java`
|
||
|
||
**排除路径配置**:
|
||
```java
|
||
.excludePathPatterns(
|
||
"/api/teacher/list", // ✅ 已排除
|
||
"/api/teacher/detail/**", // ✅ 已排除
|
||
"/api/teacher/filter-options", // ✅ 已排除
|
||
"/api/special/**", // ✅ 已排除(包含 /api/special-course/list)
|
||
"/api/interest/**", // ✅ 已排除(包含 /api/interest-course/list)
|
||
// ...
|
||
)
|
||
```
|
||
|
||
**结论**: ✅ 这三个接口都已经在排除列表中
|
||
|
||
## 前端请求配置检查
|
||
|
||
**文件**: `request.js`
|
||
|
||
**游客白名单**:
|
||
```javascript
|
||
const GUEST_ALLOWED_URLS = [
|
||
'/api/teacher/list', // ✅ 已添加
|
||
'/api/teacher/filter-options', // ✅ 已添加
|
||
'/api/special-course/list', // ✅ 已添加
|
||
'/api/interest-course/list', // ❌ 可能缺少这个
|
||
// ...
|
||
]
|
||
```
|
||
|
||
**游客模式处理**:
|
||
```javascript
|
||
// ✅ 游客访问白名单接口时不发送token
|
||
if (isGuest && isGuestAllowedUrl(options.url)) {
|
||
console.log('[Request] 游客模式,白名单接口返回401,静默失败');
|
||
reject({ code: 401, message: '未登录', silent: true });
|
||
return
|
||
}
|
||
```
|
||
|
||
## 可能的问题点
|
||
|
||
### 问题1: 前端白名单可能不完整
|
||
|
||
**检查**: `request.js` 中的 `GUEST_ALLOWED_URLS` 是否包含:
|
||
- ✅ `/api/teacher/list`
|
||
- ❓ `/api/interest-course/list` (可能缺少)
|
||
- ❓ `/api/special-course/list` (可能缺少)
|
||
|
||
### 问题2: 前端URL匹配逻辑
|
||
|
||
**当前匹配逻辑**:
|
||
```javascript
|
||
function isGuestAllowedUrl(url) {
|
||
return GUEST_ALLOWED_URLS.some(allowedUrl => url.includes(allowedUrl))
|
||
}
|
||
```
|
||
|
||
**问题**: 使用 `includes` 可能导致匹配不准确
|
||
|
||
**示例**:
|
||
- URL: `/api/interest-course/list?page=1&size=10`
|
||
- 白名单: `/api/interest-course/list`
|
||
- 匹配结果: ✅ 应该匹配成功
|
||
|
||
### 问题3: 前端实际发送的URL
|
||
|
||
**需要确认**:
|
||
- 前端实际发送的URL是什么?
|
||
- 是否包含查询参数?
|
||
- 是否与白名单中的URL匹配?
|
||
|
||
### 问题4: 后端实际返回的错误
|
||
|
||
**需要确认**:
|
||
- 后端是否真的返回401错误?
|
||
- 还是返回其他错误(如500、404)?
|
||
- 错误消息是什么?
|
||
|
||
## 诊断步骤
|
||
|
||
### 步骤1: 检查前端白名单
|
||
|
||
打开 `peidu/uniapp/src/utils/request.js`,检查 `GUEST_ALLOWED_URLS` 数组:
|
||
|
||
```javascript
|
||
const GUEST_ALLOWED_URLS = [
|
||
'/api/teacher/list', // ✅ 必须有
|
||
'/api/teacher/filter-options', // ✅ 必须有
|
||
'/api/interest-course/list', // ❓ 检查是否存在
|
||
'/api/special-course/list', // ❓ 检查是否存在
|
||
// ...
|
||
]
|
||
```
|
||
|
||
### 步骤2: 检查前端控制台
|
||
|
||
在微信开发者工具的控制台中查看:
|
||
|
||
**正常日志**:
|
||
```
|
||
[Request] 当前环境: 生产环境
|
||
[Request] BASE_URL: https://px.ddn-ai.cloud
|
||
[Request] GET URL: https://px.ddn-ai.cloud/api/teacher/list?page=1&size=10
|
||
[Request] 游客模式,白名单接口返回401,静默失败: /api/teacher/list
|
||
```
|
||
|
||
**异常日志**:
|
||
```
|
||
[Request] 401 未登录
|
||
登录已过期,请重新登录
|
||
```
|
||
|
||
### 步骤3: 检查Network请求
|
||
|
||
在微信开发者工具的Network标签中查看:
|
||
|
||
**请求信息**:
|
||
- URL: 完整的请求URL
|
||
- Method: GET
|
||
- Headers: 是否包含 Authorization
|
||
- Status: 实际返回的状态码
|
||
|
||
**响应信息**:
|
||
- Status Code: 200? 401? 500?
|
||
- Response Body: 实际返回的数据
|
||
|
||
### 步骤4: 检查后端日志
|
||
|
||
在后端控制台中查看:
|
||
|
||
**正常日志**:
|
||
```
|
||
=== JWT拦截器执行 ===
|
||
请求路径: /api/teacher/list
|
||
Authorization Header: null
|
||
token为空,放行请求
|
||
=== JWT拦截器执行完成 ===
|
||
```
|
||
|
||
**异常日志**:
|
||
```
|
||
=== JWT拦截器执行 ===
|
||
请求路径: /api/teacher/list
|
||
Authorization Header: null
|
||
token验证失败,抛出过期异常
|
||
```
|
||
|
||
## 下一步行动
|
||
|
||
### 方案1: 检查前端白名单(最可能)
|
||
|
||
如果 `GUEST_ALLOWED_URLS` 中缺少这两个URL:
|
||
- `/api/interest-course/list`
|
||
- `/api/special-course/list`
|
||
|
||
**修复**: 添加这两个URL到白名单
|
||
|
||
### 方案2: 检查前端URL匹配逻辑
|
||
|
||
如果URL匹配逻辑有问题:
|
||
|
||
**修复**: 改进匹配逻辑,使用更精确的匹配方式
|
||
|
||
### 方案3: 检查后端Service层
|
||
|
||
如果Controller没问题,可能是Service层有问题:
|
||
|
||
**检查**:
|
||
- `TeacherService.getTeacherList()`
|
||
- `InterestCourseService.getCourseList()`
|
||
- `SpecialCourseService.list()`
|
||
|
||
### 方案4: 检查数据库数据
|
||
|
||
如果Service没问题,可能是数据库没有数据:
|
||
|
||
**检查**:
|
||
```sql
|
||
-- 检查教师数据
|
||
SELECT COUNT(*) FROM teacher WHERE deleted = 0;
|
||
|
||
-- 检查兴趣课程数据
|
||
SELECT COUNT(*) FROM interest_course WHERE status = 1;
|
||
|
||
-- 检查专项课程数据
|
||
SELECT COUNT(*) FROM special_course WHERE status = 1;
|
||
```
|
||
|
||
## 总结
|
||
|
||
根据代码检查,后端的三个Controller都**不需要userId参数**,应该可以正常返回数据。
|
||
|
||
**最可能的问题**:
|
||
1. ❓ 前端白名单不完整(缺少 `/api/interest-course/list` 和 `/api/special-course/list`)
|
||
2. ❓ 前端URL匹配逻辑有问题
|
||
3. ❓ 数据库中没有数据
|
||
|
||
**建议**: 先检查前端的 `request.js` 文件,确认白名单是否完整。
|