6.4 KiB
6.4 KiB
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. 根本原因
-
认证时机问题:
- 前端在logout时先调用SSE关闭接口,再调用logout接口
- 此时token可能已经失效或即将失效
- 后端
LoginHelper.getUserId()可能返回null
-
后端接口设计问题:
- SSE关闭接口使用了
@SaIgnore注解,但仍然需要获取用户信息 - 缺少对空值和异常的处理
- 没有优雅降级机制
- SSE关闭接口使用了
-
nginx代理配置问题:
- SSE关闭接口可能没有正确的代理配置
- 缺少专门的错误处理
🛠️ 解决方案
方案一:修复后端SSE关闭接口(已实施)
1. 优化错误处理
/**
* 关闭 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. 添加错误处理
/**
* 注销
*/
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关闭接口专用配置
# 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. 更新后端代码
# 重新编译后端项目
mvn clean compile
# 重启后端服务
systemctl restart your-backend-service
2. 更新前端代码
# 重新构建前端项目
npm run build
# 部署到nginx目录
cp -r dist/* /root/hzdyjsweb9091/dist/
3. 更新nginx配置
# 测试nginx配置
nginx -t
# 重新加载配置
nginx -s reload
🔧 验证方法
1. 功能验证
- 正常登录:确保用户能够正常登录
- SSE连接:检查SSE连接是否正常建立
- 正常退出:测试用户退出流程
- 错误处理:检查控制台是否有错误信息
2. 错误场景测试
- Token失效退出:在token即将失效时退出
- 网络异常退出:在网络不稳定的情况下退出
- 并发退出:多个用户同时退出
3. 日志检查
# 检查后端日志
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连接管理
- 用户体验:添加退出进度提示
- 错误恢复:实现自动重试机制
更新时间:2025-01-03
维护人员:系统管理员
文档版本:v1.0