我在spring中有一个控制器,它获取异步处理的POST请求(使用DeferredResult
对象作为返回值(。
此请求的响应是直接向HTTP流写入字节(HttpServletResponse.getWriter().print()
(,当写入完成时,它会在DeferredResult
对象上设置关闭连接的结果。
我正在以流块的形式写我的回复。我在处理这个请求时遇到了问题,因为如果我有1分钟没有写信给客户端,客户端就会关闭连接。(我可以写一些区块,然后停止写1分钟——因此,连接将在我的过程中关闭(。
我想控制关闭连接的过程——我想在不向流写入任何数据时发送keep alive
,这样在我决定从服务器端关闭连接之前,连接不会关闭。
我不知道我应该如何从服务器中的控制器获得对连接的控制。请协助。谢谢
在HTTP中,在正在进行的请求或响应过程中没有"保持活动"这一功能,这有助于在接收请求或响应时解决空闲超时问题。
HTTP保持活动只是在响应后保持TCP连接打开,以便在同一连接上处理更多请求。TCP keep-alive用于在不关闭TCP的情况下检测连接丢失,也可用于防止客户端和服务器之间的有状态数据包过滤器(如防火墙或NAT路由器中使用的(中的空闲超时。但是,它不能防止应用程序级别的空闲超时,因为它不传输应用程序级别可见的任何数据。
请注意,您想要使用HTTP的方式与HTTP最初的设计方式相反。它是为客户端发送完整请求,服务器立即发送完整响应而设计的,而不是为服务器发送部分响应,空闲一段时间,然后再发送更多。实现这种行为的正确方法是使用WebSockets。有了WebSockets,客户端和服务器都可以随时发送新消息(即无请求-响应模式(,而且它还支持保持活动消息。如果WebSockets不是一个选项,那么您可以实现一个轮询客户端,该客户端定期通过新请求从服务器轮询新数据。
我最近也遇到了类似的需求。服务器代码执行一个长时间运行的操作,可能需要长达30分钟的时间才能返回,而客户端在这之前很久就超时了。解决方案是让长时间运行的操作定期发送";保持活力";数据包通过一个"网络"发送到客户端;回调";请求处理程序方法提供的参数。回调只不过是一个函数(想想Java中的Lambda(,它将";保持活力";数据包发送到客户端,然后通过可以从javax.servlet.http.HttpServletResponse
中获得的java.io.PrintWriter
引用将该数据包写入客户端。下面的代码是执行此操作的处理程序方法。我不得不重构调用层次结构中的代码,以接受这个新的";回调";参数,直到";回调";可以到达执行长时间运行的操作的方法;回调";每隔一段时间,例如每处理10条记录。下面并不是Groovy代码(在JVM上运行的Java之上的脚本代码(,服务器端框架是Spring,
...
@Autowired
DataImporter dataImporter
@PostMapping("/my/endpoint")
void importData(@RequestBody MyDto myDto, HttpServletResponse response) {
// Callback to allow servant code deep in the call hierarchy to report back to client any arbitrary message
Closure<Void> callback = { String str ->
response.writer.print str
response.writer.flush()
}
// This leads to the code that is performing a long running operation. Using
// this "hook" that code has a direct connection to the client whereby
// it can send packets of data to keep the connection from timing out.
dataImporter.importData(myDto, callback)
}
}