编码 / 解码

Encoding / Decoding

The HTTP spec defines a Content-Encoding header, which signifies whether the entity body of an HTTP message is “encoded” and, if so, by which algorithm. The only commonly used content encodings are compression algorithms.

HTTP 规范 定义了一个 Content-Encoding 头域,表示一个 HTTP 消息的实体正文是否已“编码”,如果是的话,用的哪种算法。常用的内容编码是压缩算法。

Currently, Akka HTTP supports the compression and decompression of HTTP requests and responses with the gzip or deflate encodings. The core logic for this lives in the akka.http.scaladsl.coding package.akka.http.javadsl.coding.Coder enum class.

当前,Akka HTTP 支持使用 gzipdeflate 编码对 HTTP 请求和响应进行压缩和解压缩。 核心逻辑在 akka.http.scaladsl.codingakka.http.javadsl.coding.Coder 枚举 里。

Server side

服务器端

The support is not enabled automatically, but must be explicitly requested. For enabling message encoding/decoding with Routing DSL see the CodingDirectives.

该支持不是自动启用的,必须明确地请求。使用 Routing DSL 启用消息编码/解码,请见 CodingDirectives

Client side

客户端

There is currently no high-level or automatic support for decoding responses on the client-side.

当前,对于客户端响应解码没有高级或自动支持。

The following example shows how to decode responses manually based on the Content-Encoding header:

下面的例子显示了怎样基于 Content-Encoding 头域手动解码响应:

Scala
import akka.actor.ActorSystem
import akka.http.scaladsl.Http
import akka.http.scaladsl.coding.{ Gzip, Deflate, NoCoding }
import akka.http.scaladsl.model._, headers.HttpEncodings
import akka.stream.ActorMaterializer

import scala.concurrent.Future

implicit val system = ActorSystem()
implicit val materializer = ActorMaterializer()
import system.dispatcher

val http = Http()

val requests: Seq[HttpRequest] = Seq(
  "https://httpbin.org/gzip", // Content-Encoding: gzip in response
  "https://httpbin.org/deflate", // Content-Encoding: deflate in response
  "https://httpbin.org/get" // no Content-Encoding in response
).map(uri => HttpRequest(uri = uri))

def decodeResponse(response: HttpResponse): HttpResponse = {
  val decoder = response.encoding match {
    case HttpEncodings.gzip =>
      Gzip
    case HttpEncodings.deflate =>
      Deflate
    case HttpEncodings.identity =>
      NoCoding
  }

  decoder.decodeMessage(response)
}

val futureResponses: Future[Seq[HttpResponse]] =
  Future.traverse(requests)(http.singleRequest(_).map(decodeResponse))

futureResponses.futureValue.foreach { resp =>
  system.log.info(s"response is ${resp.toStrict(1.second).futureValue}")
}

system.terminate()
Java
import akka.actor.ActorSystem;
import akka.http.javadsl.Http;
import akka.http.javadsl.coding.Coder;
import akka.http.javadsl.model.HttpRequest;
import akka.http.javadsl.model.HttpResponse;
import akka.http.scaladsl.model.headers.HttpEncodings;
import akka.stream.ActorMaterializer;
import akka.stream.Materializer;
import scala.concurrent.duration.FiniteDuration;

import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.stream.Collectors;

public class HttpClientDecodingExampleTest {

  public static void main(String[] args) throws Exception {

    final ActorSystem system = ActorSystem.create();
    final Materializer materializer = ActorMaterializer.create(system);

    final List<HttpRequest> httpRequests = Arrays.asList(
      HttpRequest.create("https://httpbin.org/gzip"), // Content-Encoding: gzip in response
      HttpRequest.create("https://httpbin.org/deflate"), // Content-Encoding: deflate in response
      HttpRequest.create("https://httpbin.org/get") // no Content-Encoding in response
    );

    final Http http = Http.get(system);

    final Function<HttpResponse, HttpResponse> decodeResponse = response -> {
      // Pick the right coder
      final Coder coder;
      if (HttpEncodings.gzip().equals(response.encoding())) {
        coder = Coder.Gzip;
      } else if (HttpEncodings.deflate().equals(response.encoding())) {
        coder = Coder.Deflate;
      } else {
        coder = Coder.NoCoding;
      }

      // Decode the entity
      return coder.decodeMessage(response);
    };

    List<CompletableFuture<HttpResponse>> futureResponses = httpRequests.stream()
      .map(req -> http.singleRequest(req, materializer)
        .thenApply(decodeResponse))
      .map(CompletionStage::toCompletableFuture)
      .collect(Collectors.toList());

    for (CompletableFuture<HttpResponse> futureResponse : futureResponses) {
      final HttpResponse httpResponse = futureResponse.get();
      system.log().info("response is: " + httpResponse.entity()
                        .toStrict(1000, materializer)
                        .toCompletableFuture()
                        .get());
    }

    system.terminate();
  }
}
在此文档中发现错误?该页面的源代码可以在 这里 找到。欢迎随时编辑并提交 Pull Request。