fix: listByConversation 在 conversation 不存在时返回空列表而非抛异常

This commit is contained in:
2026-06-28 22:40:13 +08:00
parent caaeb94477
commit e3eb1afbb0
3 changed files with 95 additions and 3 deletions
+81
View File
@@ -266,6 +266,37 @@ bash deploy-all.sh admin
---
## 部署强制规则(最高优先级,不可违反)
**本地开发完成、验证通过、验收没有问题后,必须执行 `deploy.py` 部署脚本,将应用部署到服务器上。**
### 强制流程
每次功能开发或 bug 修复完成后,必须按以下顺序操作:
1. **本地验证**:在本地开发环境中完成功能开发和自测,确认无报错。
2. **验收通过**:按"服务器端验收强制规则"完成验收,确认功能正常。
3. **执行部署**:验收通过后,立即执行部署脚本将应用部署到服务器:
- 后端:`python deploy.py backend`
- 前端:`python deploy.py frontend`
- 管理后台:`python deploy.py admin`
- 全部:`python deploy.py all`
4. **部署验证**:部署完成后,在服务器上验证功能正常,无报错。
### 禁止行为
- ❌ 禁止本地开发完成后不部署到服务器就认为任务完成
- ❌ 禁止跳过验收直接部署
- ❌ 禁止部署后不验证就结束任务
- ❌ 禁止在编译或验收有报错的情况下部署
### 允许的唯一例外
- ✅ 纯文档修改(不涉及代码变更)
- ✅ 仅在本地运行的脚本工具(不涉及线上服务)
---
## 本地服务管理规则(强制)
**启动、重启、停止本地前后端服务时,必须使用项目根目录下的 `dev-services.py` 脚本。**
@@ -384,3 +415,53 @@ bash deploy-all.sh admin
- 关键业务操作必须记录操作日志
- 异常信息要包含足够的上下文信息
- 生产环境禁止输出 debug 级别日志
---
## 日志排查规则(强制)
**遇到"对话不存在或无权限"错误时,按以下顺序排查:**
### 1. 检查 conversationId 是否为空
- **前端检查**:在浏览器 DevTools Network 面板查看请求参数 `conversationId`
- **后端检查**:查看 `UserContextHolder.getCurrentUserId()` 是否返回有效值
- **数据库检查**:执行 `SELECT * FROM t_conversation WHERE id = '<conversationId>'` 确认对话是否存在
### 2. 检查权限匹配
- **前端问题**:当前登录用户的 userId 与对话的 userId 不一致
- **后端逻辑**`ScriptMessageServiceImpl.listByConversation` 中会校验 `conversation.getUserId().equals(currentUserId)`
- **修复方案**:确认前端传递的是正确的 conversationId,或重新创建对话
### 3. 常见原因
| 原因 | 解决方案 |
|------|----------|
| conversationId 为空字符串 | 前端增加短路保护,显示"暂无对话记录"提示 |
| 对话不存在(已删除) | 引导用户创建新对话 |
| 用户未登录 | 检查 Token 是否有效,重新登录 |
| 对话属于其他用户 | 确认前端传递的 conversationId 正确 |
### 4. 快速定位方法
使用 `tools/download-server-log.py` 脚本下载服务器日志:
```bash
# 下载完整日志
python tools/download-server-log.py latest
# 只看最近 50 条错误
python tools/download-server-log.py errors 50
# 搜索特定关键词(如 listByConversation
python tools/download-server-log.py grep "listByConversation" 20
```
日志位置:`logs/server/` 目录
### 5. 防御性编程原则
- **Service 层**:对空参数做防御性检查,返回空列表而非抛异常
- **Controller 层**:参数校验失败时返回友好错误提示
- **前端**:接口调用前做空值检查,避免发送无效请求
+5 -1
View File
@@ -661,7 +661,11 @@ const continueCurrentVersion = () => {
}
const loadMessages = async () => {
if (!conversationId.value) return
// 短路保护:conversationId 为空时不请求接口,显示友好提示
if (!conversationId.value) {
uni.showToast({ title: '暂无对话记录', icon: 'none' })
return
}
try {
const res = await listMessagesByConversation({ conversationId: conversationId.value, includeVersions: false })
messages.value = res.data || []
@@ -38,8 +38,15 @@ public class ScriptMessageServiceImpl implements ScriptMessageService {
public List<MessageResponse> listByConversation(String conversationId, boolean includeVersions) {
String currentUserId = UserContextHolder.getCurrentUserId();
Conversation conversation = conversationService.getById(conversationId);
if (conversation == null || !conversation.getUserId().equals(currentUserId)) {
throw new IllegalStateException("对话不存在或无权限");
// 对话不存在:视为"尚无消息",返回空列表(前端用临时 ID 查询时走这条分支)
if (conversation == null) {
return java.util.Collections.emptyList();
}
// 对话存在但归属他人:权限问题,必须暴露
if (!conversation.getUserId().equals(currentUserId)) {
throw new IllegalStateException("无权限访问该对话");
}
LambdaQueryWrapper<Message> wrapper = new LambdaQueryWrapper<>();