HttpServletResponse调用sendRedirect无法执行,报错响应已提交问题求助
错误根本原因
你遇到的response is already committed报错的核心原因是:HTTP协议是请求-响应模式的短连接协议,当你的addSolution方法返回ResponseEntity对象时,该PUT请求的完整响应已经被发送给客户端,对应的HttpServletResponse生命周期已经结束,TCP连接也已关闭,后续定时任务再持有这个过期的Response对象操作重定向,必然会抛出异常。
原有设计的其他问题
- Spring控制器默认是单例模式,你在类中定义的
start、time、myResponse都是全局成员变量,多用户同时发起请求时变量会互相覆盖,完全无法正常使用。 - 服务端的
@Scheduled定时任务和客户端的请求生命周期完全解耦,服务端单方面发起的重定向指令根本无法送达已经结束的HTTP请求对应的客户端。
正确实现方案
根据你的使用场景选择对应方案即可:
方案1:使用HTTP Refresh响应头(适配浏览器场景,最简便)
直接在PUT请求的响应头中添加Refresh字段,告诉浏览器1分钟后自动跳转到目标地址,不需要服务端任何定时任务,修改addSolution方法即可:
@PutMapping("/maths/answer") public ResponseEntity<Object> addSolution(@RequestBody MathsAnswer from, HttpServletResponse res){ // 原有业务逻辑不变 Object result = service.addSolution(from); // 添加响应头,60秒后跳转到/timeUp HttpHeaders headers = new HttpHeaders(); headers.add("Refresh", "60; url=/timeUp"); return new ResponseEntity<>(result, headers, HttpStatus.OK); }
方案2:前端主动计时跳转(适配前后端分离场景,兼容性最好)
前端调用完PUT接口拿到200响应后,自行通过setTimeout计时1分钟,主动跳转到/timeUp地址,不需要服务端做任何额外逻辑。
方案3:WebSocket长连接方案(适配需要服务端主动推送的场景)
如果必须由服务端控制跳转时机,你需要先让客户端和服务端建立WebSocket长连接,PUT请求处理完成后记录客户端标识和开始时间,1分钟后服务端通过WebSocket向对应客户端推送跳转指令,客户端收到指令后再执行跳转操作。
内容的提问来源于stack exchange,提问作者Chinedu
相关产品推荐
相关产品推荐

