在spring服务器中发送长异步请求时保持活动状态

Posted

技术标签:

【中文标题】在spring服务器中发送长异步请求时保持活动状态【英文标题】:send keep alive on long asynchronous request in spring server 【发布时间】:2019-10-31 15:06:15 【问题描述】:

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

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

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

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

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

【问题讨论】:

【参考方案1】:

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

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

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

【讨论】:

【参考方案2】:

我最近遇到了类似的需求。服务器代码执行一个长时间运行的操作,可能需要长达 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)
  

【讨论】:

闭包类来自哪个包? @AkhilJain 这里,'groovy.lang.Closure',在 Maven 工件 '/org/codehaus/groovy/groovy-all/2.4.15/groovy-all-2.4.15.jar 中找到! /groovy/lang/Closure.class'。在我的工作中,我们的 Maven 被配置为使用 Groovy 作为编程语言。如果您使用的是纯 Java,则可以使用“docs.oracle.com/javase/8/docs/api/java/util/function/…”接口实现 Lambda,以实现与上述闭包类似的效果。如果您需要样品,请告诉我。 是的,我一直在寻找 Java 代码,后来发布它是 groovy 代码。

以上是关于在spring服务器中发送长异步请求时保持活动状态的主要内容,如果未能解决你的问题,请参考以下文章

服务器断开连接后如何在 Spring MVC 中保持客户端会话处于活动状态

HTTP 保持活动状态和 TCP 保持活动状态

Socket 两种连接方式

发送消息后保持 textarea 处于活动状态

如何在请求后使 IdentityDbContext 保持活动状态,以便服务可以使用 UserManager 完成其任务?

长连接、短连接是啥意思?哪位大神给讲一下,不要太官方了,通俗易懂点,谢谢。