我正在使用 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))
}
首先,让我们了解导致代码中出现问题的原因。
当您调用
res.json
时,您是在告诉 Play 消耗整个响应,将其解析为 JSON,将其保留在内存中,然后才能将其发送回来。
这不是你想做的事。
相反,您可以将响应解析为
Source
(Akka Stream),以便延迟/渐进地使用它。
做这样的事情:
val response = ws.url(...).withMethod("POST").stream()
val bodyStream = response.map(_.bodyAsSource())
bodyStream.map(Ok.chunked)