我正在使用Play框架将请求转发到一些内部服务。其中一个服务返回相当大的有效负载(5MB json数据)。当我直接调用服务时,处理和返回请求大约需要5秒(正在进行一些处理)。当我使用play转发请求并返回响应时,需要3倍的时间。我还得到了一些java.lang.OutOfMemoryError: Java heap space at play.shaded.ahc.org.asynchttpclient.netty.NettyResponse.getResponseBodyAsByteBuffer
错误,这是怀疑来自解析json体,这是不必要的。有没有办法转发请求并返回响应而不解析它?
目前我的代码看起来像这样:
def process = Authorized().async { request =>
request.body.asJson.map { body =>
ws.url("internal-service/process")
.addHttpHeaders("Accept-Encoding" -> "gzip, deflate")
.post(body).map { res =>
if (res.status >= 200 && res.status < 300) {
Ok(res.json)
} else {
throw SimpleServiceException(s"Failed to process datasets. Reason ${res.status}: ${res.body}")
}
}
}.getOrElse(Future.successful(BadRequest))
}
1条答案
按热度按时间7jmck4yq1#
首先,让我们了解是什么导致了代码中的问题。
当你调用
res.json
时,你告诉Play完全使用响应,将其解析为JSON,将其保存在内存中,然后能够将其发送回来。这不是你想做的。
相反,您可以将响应解析为
Source
(Akka流),以便延迟/渐进地使用它。请执行以下操作:
最重要的两件事是:
.withMethod(...).stream()
而不是.post()
来获取流响应Ok.chunked(...)
流回客户端有关详细信息,请参阅此有用的文档。它甚至包含了一个代码示例,用于您想要做的事情:
响应体的另一个常见目的地是将它们从控制器的Action流回:
你可能已经注意到了,在调用stream()之前,我们需要通过对请求调用withMethod来设置要使用的HTTP方法。