/ / Akka HTTPでgzipされたJSONのデコード/デコード - json、scala、akka-http

Akka HTTPでgzipされたJSONをデコードする - json、scala、akka-http

私達が呼べるエンドポイントがあります /test サードパーティのAPIから内部的にデータを取得するそして、応答を返す前に何らかの変換を行いたいと考えています。私がハングアップしているのは、このサードパーティのAPIがgzipされたJSONを返しており、(まだ)それをデコードできないことです。 decodeRequestディレクティブ しかし、私は自分のルーティングでこれを使用しなければならないようで、私はここでより深いレベルにいます。を受け取ったときに呼び出す内部メソッドがあります。 GET 私のエンドポイントへ /test という名前 do3rdPartyAPIRequest 私が構築するところ HttpRequest そしてに渡る Http().singleRequest() だからその見返りに私は持っている Future[HttpResponse] それが私が私がなりたいと思う場所ですが、私はここで立ち往生しています。

いくつかのローカルAPIを使用して、同様の方法で構築および使用したので、応答をエンコードすることはできませんでした。 Future[HttpResponse] レスポンスのステータスを確認してからJSONに変換します。 Unmarshal しかし、JSONに変換する前に私が知る限り、これには追加のステップが必要です。私はこの質問は非常によく似ていると思います これです しかしそれはスプレー特有であり、私はこの答えを現在のakka httpに翻訳することができなかった。

回答:

回答№1は6

最後にこれを考え出した - これは応答からバイト文字列を取得するための絶対的な最善ではないかもしれませんがそれは動作します..あなたが使用できることがわかった Gzipクラス

そして2つの選択肢があります

  1. Gzip.decode
  2. 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])
}

回答№2については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]
}
}
})