252 lines
6.4 KiB
Markdown
252 lines
6.4 KiB
Markdown
# SSE关闭接口406错误解决方案
|
||
|
||
## 🚨 问题描述
|
||
|
||
用户在前台退出时,SSE关闭接口返回406 Not Acceptable错误:
|
||
|
||
```
|
||
Request URL: http://hzdyjsweb.camasort.com/prod-api/resource/sse/close
|
||
Request Method: GET
|
||
Status Code: 406 Not Acceptable
|
||
```
|
||
|
||
## 🔍 问题分析
|
||
|
||
### 1. 错误原因分析
|
||
|
||
**406 Not Acceptable错误**通常表示:
|
||
- 服务器无法根据请求的内容特性完成请求
|
||
- 请求的资源的内容特性无法满足请求头中的条件
|
||
- 用户认证信息缺失或无效
|
||
|
||
### 2. 根本原因
|
||
|
||
1. **认证时机问题**:
|
||
- 前端在logout时先调用SSE关闭接口,再调用logout接口
|
||
- 此时token可能已经失效或即将失效
|
||
- 后端`LoginHelper.getUserId()`可能返回null
|
||
|
||
2. **后端接口设计问题**:
|
||
- SSE关闭接口使用了`@SaIgnore`注解,但仍然需要获取用户信息
|
||
- 缺少对空值和异常的处理
|
||
- 没有优雅降级机制
|
||
|
||
3. **nginx代理配置问题**:
|
||
- SSE关闭接口可能没有正确的代理配置
|
||
- 缺少专门的错误处理
|
||
|
||
## 🛠️ 解决方案
|
||
|
||
### 方案一:修复后端SSE关闭接口(已实施)
|
||
|
||
#### 1. 优化错误处理
|
||
|
||
```java
|
||
/**
|
||
* 关闭 SSE 连接
|
||
*/
|
||
@SaIgnore
|
||
@GetMapping(value = "${sse.path}/close")
|
||
public R<Void> close() {
|
||
try {
|
||
// 尝试获取token和用户ID,如果获取失败则直接返回成功
|
||
String tokenValue = null;
|
||
Long userId = null;
|
||
|
||
try {
|
||
tokenValue = StpUtil.getTokenValue();
|
||
userId = LoginHelper.getUserId();
|
||
} catch (Exception e) {
|
||
// 如果获取用户信息失败,记录日志但不抛出异常
|
||
log.warn("Failed to get user info for SSE close: {}", e.getMessage());
|
||
return R.ok();
|
||
}
|
||
|
||
// 如果token或userId为空,直接返回成功
|
||
if (tokenValue == null || userId == null) {
|
||
log.info("Token or userId is null, skipping SSE disconnect");
|
||
return R.ok();
|
||
}
|
||
|
||
sseEmitterManager.disconnect(userId, tokenValue);
|
||
return R.ok();
|
||
} catch (Exception e) {
|
||
log.error("Error during SSE close: {}", e.getMessage(), e);
|
||
// 即使出错也返回成功,避免影响用户退出流程
|
||
return R.ok();
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 2. 关键改进点
|
||
|
||
- **添加异常捕获**:捕获所有可能的异常
|
||
- **空值检查**:检查token和userId是否为空
|
||
- **优雅降级**:即使出错也返回成功状态
|
||
- **日志记录**:记录详细的错误信息用于调试
|
||
|
||
### 方案二:优化前端logout逻辑(已实施)
|
||
|
||
#### 1. 添加错误处理
|
||
|
||
```typescript
|
||
/**
|
||
* 注销
|
||
*/
|
||
export function logout() {
|
||
// 先尝试关闭SSE连接,但不阻塞logout流程
|
||
if (import.meta.env.VITE_APP_SSE === 'true') {
|
||
request({
|
||
url: '/resource/sse/close',
|
||
method: 'get'
|
||
}).catch((error) => {
|
||
// SSE关闭失败不影响用户退出,只记录日志
|
||
console.warn('SSE close failed during logout:', error);
|
||
});
|
||
}
|
||
|
||
// 执行正常的logout流程
|
||
return request({
|
||
url: '/auth/logout',
|
||
method: 'post'
|
||
});
|
||
}
|
||
```
|
||
|
||
#### 2. 关键改进点
|
||
|
||
- **非阻塞调用**:SSE关闭失败不影响logout流程
|
||
- **错误捕获**:捕获SSE关闭接口的错误
|
||
- **日志记录**:记录错误信息但不影响用户体验
|
||
|
||
### 方案三:更新nginx配置(已实施)
|
||
|
||
#### 1. 添加SSE关闭接口专用配置
|
||
|
||
```nginx
|
||
# SSE关闭接口专用配置
|
||
location ^~ /prod-api/resource/sse/close {
|
||
proxy_pass http://47.121.125.41:8080/resource/sse/close;
|
||
proxy_set_header Host $host;
|
||
proxy_set_header X-Real-IP $remote_addr;
|
||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||
proxy_set_header X-Forwarded-Proto $scheme;
|
||
|
||
# 普通API配置(不需要SSE特殊配置)
|
||
proxy_connect_timeout 30s;
|
||
proxy_send_timeout 30s;
|
||
proxy_read_timeout 30s;
|
||
|
||
# CORS处理
|
||
add_header Access-Control-Allow-Origin *;
|
||
add_header Access-Control-Allow-Methods 'GET, POST, PUT, DELETE, OPTIONS';
|
||
add_header Access-Control-Allow-Headers 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization,clientid';
|
||
add_header Access-Control-Allow-Credentials true;
|
||
|
||
if ($request_method = 'OPTIONS') {
|
||
return 204;
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 2. 配置说明
|
||
|
||
- **独立配置**:为SSE关闭接口提供独立的代理配置
|
||
- **合理超时**:设置30秒超时,适合普通API调用
|
||
- **CORS支持**:确保跨域请求正常工作
|
||
|
||
## 📋 部署步骤
|
||
|
||
### 1. 更新后端代码
|
||
|
||
```bash
|
||
# 重新编译后端项目
|
||
mvn clean compile
|
||
|
||
# 重启后端服务
|
||
systemctl restart your-backend-service
|
||
```
|
||
|
||
### 2. 更新前端代码
|
||
|
||
```bash
|
||
# 重新构建前端项目
|
||
npm run build
|
||
|
||
# 部署到nginx目录
|
||
cp -r dist/* /root/hzdyjsweb9091/dist/
|
||
```
|
||
|
||
### 3. 更新nginx配置
|
||
|
||
```bash
|
||
# 测试nginx配置
|
||
nginx -t
|
||
|
||
# 重新加载配置
|
||
nginx -s reload
|
||
```
|
||
|
||
## 🔧 验证方法
|
||
|
||
### 1. 功能验证
|
||
|
||
1. **正常登录**:确保用户能够正常登录
|
||
2. **SSE连接**:检查SSE连接是否正常建立
|
||
3. **正常退出**:测试用户退出流程
|
||
4. **错误处理**:检查控制台是否有错误信息
|
||
|
||
### 2. 错误场景测试
|
||
|
||
1. **Token失效退出**:在token即将失效时退出
|
||
2. **网络异常退出**:在网络不稳定的情况下退出
|
||
3. **并发退出**:多个用户同时退出
|
||
|
||
### 3. 日志检查
|
||
|
||
```bash
|
||
# 检查后端日志
|
||
tail -f /path/to/backend/logs/application.log | grep -i "sse"
|
||
|
||
# 检查nginx错误日志
|
||
tail -f /var/log/nginx/hzdyjsweb.camasort.com.error.log
|
||
```
|
||
|
||
## 🎯 预期效果
|
||
|
||
### 1. 问题解决
|
||
|
||
- ✅ 消除406错误
|
||
- ✅ 用户退出流程顺畅
|
||
- ✅ 不影响用户体验
|
||
|
||
### 2. 系统稳定性
|
||
|
||
- ✅ SSE连接正确关闭
|
||
- ✅ 资源正确释放
|
||
- ✅ 错误处理完善
|
||
|
||
### 3. 监控指标
|
||
|
||
- SSE关闭成功率:100%
|
||
- 用户退出成功率:100%
|
||
- 错误日志减少:显著减少
|
||
|
||
## 📚 相关文档
|
||
|
||
- [SSE生产环境配置问题解决方案](../SSE生产环境配置问题解决方案.md)
|
||
- [nginx配置文档](../../部署文档/nginx配置/)
|
||
- [前端环境变量配置建议](../../部署文档/nginx配置/前端环境变量配置建议.md)
|
||
|
||
## 🔄 后续优化
|
||
|
||
1. **监控告警**:添加SSE关闭失败监控
|
||
2. **性能优化**:优化SSE连接管理
|
||
3. **用户体验**:添加退出进度提示
|
||
4. **错误恢复**:实现自动重试机制
|
||
|
||
---
|
||
|
||
**更新时间**:2025-01-03
|
||
**维护人员**:系统管理员
|
||
**文档版本**:v1.0 |