我有一个端点,我们可以调用/test
,在内部从第三方API获取数据,然后在返回响应之前进行一些转换。我挂断的地方是这个第三方API正在返回gzip压缩的JSON,我还无法解码它(还)。我找到了decodeRequest directive,但似乎我必须在我的路由中使用它,我在这里更深层次。我有一个内部方法,一旦我收到GET
到我的端点/test
,其名为do3rdPartyAPIRequest
,我在其中建立一个HttpRequest
并传递给Http().singleRequest()
所以作为回报,我有Future[HttpResponse]
这是我认为我想成为的地方,但我被困在这里。
对于我以类似方式构建和使用的一些本地API,我没有编码我的响应,因此通常使用Future[HttpResponse]
我检查响应状态并通过Unmarshal
转换为JSON但是这样在转换为JSON之前,我需要一个额外的步骤。我意识到这个问题与this one非常相似,但这是喷涂特定的,我无法将此答案转换为当前的akka http
答案 0 :(得分:6)
最后想出来了 - 这可能不是从响应中获取字节串的绝对最佳但它可以工作..原来你可以使用Gzip class
你有两个选择
Gzip.decode
Gzip.decoderFlow
以下是我的示例,以防这对您有所帮助:
def getMyDomainObject(resp: HttpResponse):Future[MyDomain] = {
for {
byteString <- resp.entity.dataBytes.runFold(ByteString(""))(_ ++ _)
decompressedBytes <- Gzip.decode(byteString)
result <- Unmarshal(decompressedBytes).to[MyDomain]
} yield result
}
def getMyDomainObjectVersion2(resp:HttpResponse):Future[MyDomain] = {
resp.entity.dataBytes
.via(Gzip.decoderFlow)
.runWith(Sink.head)
.flatMap(Unmarshal(_).to[MyDomain])
}
答案 1 :(得分:2)
您可能希望压缩内容默认由akka-http管理,但它只提供PredefinedFromEntityUnmarshallers
,而实体内部没有Content-encoding
标头的信息。
要解决此问题,您必须实现自己的Unmarshaller并将其纳入范围
示例:
implicit val gzipMessageUnmarshaller = Unmarshaller(ec => {
(msg: HttpMessage) => {
val `content-encoding` = msg.getHeader("Content-Encoding")
if (`content-encoding`.isPresent && `content-encoding`.get().value() == "gzip") {
val decompressedResponse = msg.entity.transformDataBytes(Gzip.decoderFlow)
Unmarshal(decompressedResponse).to[String]
} else {
Unmarshal(msg).to[String]
}
}
})