1

我在春天有一个控制器,它获取一个作为异步处理的 POST 请求(使用DeferredResult对象作为返回值)。

此请求的响应是直接将字节写入 HTTP 流(HttpServletResponse.getWriter().print()),当它完成写入时,它会在DeferredResult对象上设置结果以关闭连接。

我正在以流块的形式写我的回复。我在此请求处理中遇到问题,因为如果我在 1 分钟内不写信,客户端将关闭连接。(我可以写一些块然后停止写 1 分钟 - 因此连接将在我的过程中间关闭)。

我想控制关闭连接过程 - 我想keep alive在不向流中写入任何数据时发送,以便在我决定从服务器端关闭连接之前不会关闭连接。

我不知道如何从服务器中的控制器控制连接。请协助。谢谢。

4

2 回答 2

2

在 HTTP 中正在进行的请求或响应期间没有“保持活动”之类的东西,它可以帮助在接收请求或响应时空闲超时。

HTTP keep alive 只是在响应后保持 TCP 连接打开,以便在同一连接上处理更多请求。相反,TCP 保持活动用于检测连接丢失而无需关闭 TCP,也可用于防止客户端和服务器之间的有状态数据包过滤器(如在防火墙或 NAT 路由器中使用)中的空闲超时。但它并不能防止应用程序级别的空闲超时,因为它不传输任何对应用程序级别可见的数据。

请注意,您希望使用 HTTP 的方式与最初设计 HTTP 的方式相反。它是为客户端发送完整请求而服务器立即发送完整响应而设计的,而不是为服务器发送响应的某些部分而设计的,空闲一段时间然后发送更多。实现这种行为的正确方法是使用 WebSockets。使用 WebSockets,客户端和服务器都可以随时发送新消息(即没有请求-响应模式),它还支持保持活动消息。如果 WebSockets 不是一个选项,您可以改为实现一个轮询客户端,该客户端通过新请求定期从服务器轮询新数据。

于 2019-10-31T15:30:49.487 回答
0

我最近遇到了类似的需求。服务器代码执行一个长时间运行的操作,可能需要长达 30 分钟才能返回,而客户端在此之前很久就超时了。解决方案是让长时间运行的操作通过请求处理程序方法提供的“回调”参数定期向客户端发送“保持活动”数据包。回调只不过是一个函数(想想 Java 中的 Lambda),它将“保持活动”数据包作为参数发送到客户端,然后通过java.io.PrintWriter引用将该数据包写入客户端,您可以从中获取javax.servlet.http.HttpServletResponse. 下面的代码是执行此操作的处理程序方法。我必须重构调用层次结构中的代码以接受这个新的“回调”参数,直到“回调”可以到达执行长时间运行操作的方法,并且在该代码中我每隔一段时间调用一次“回调”,因为每次处理 10 条记录时的示例。并不是说下面是 Groovy 代码(在 Java 之上运行在 JVM 上的脚本代码)并且服务器端框架是 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)
  }
}
于 2020-12-10T19:55:22.520 回答