Akka http流式传输响应标头

问题描述 投票:0回答:1

根据定义,http响应被分成3个partsstatus-code -> headers -> body,并且当执行akka客户端http请求时,在完全接收到前两个部分之后接收到http响应。

  val responseFuture: Future[HttpResponse]
  responseFuture.map {
    case HttpResponse(statusCode:StatusCode, headers:Seq[HttpHeader], entity:ResponseEntity, protocol:HttpProtocol)
  }

对于大多数用例来说这是完全正常的,但在我的特定情况下,我需要在收到所有标头之前访问标头(第三方服务器通过编写自定义进度标头返回进度,直到响应准备就绪)。有没有办法像访问正文一样访问标题?

  val entity: ResponseEntity
  val entitySource:Source[ByteString, Any] = entity.dataBytes

在完美的世界中,有一种方法可以访问标题作为源

HttpResponse(statusCode:StatusCode, headers:Source[HttpHeader, NotUsed], entity:ResponseEntity, protocol:HttpProtocol)
akka akka-stream akka-http
1个回答
1
投票

akka-http不可能

representation of HttpResponse将标题视为Seq[HttpHeader]而不是Iteratorakka-stream Source。因此,正如问题中所解释的那样,如果没有首先获得所有标头值,则无法实例化HttpResponse对象。

我不知道这个设计决定背后的确切原因,但我怀疑这是因为支持标题的Source和身体的Source很难。如果没有首先使用标头Source,就无法使用正文Source,因此必须严格按顺序访问响应的成员变量。这会导致混淆和意外错误。

使用akka-stream进行低级处理

hypertext transfer protocol只是一个应用层协议,通常在TCP之上。而且,这是一个相当simple message format

响应消息包含以下内容:

  • 状态行,包括状态代码和原因消息(例如,HTTP / 1.1 200 OK,表示客户端的请求成功)。
  • 响应头字段(例如,Content-Type:text / html)。
  • 空行。
  • 可选的邮件正文。

因此,您可以使用Tcp绑定来获取连接并自己解析消息ByteString Source来获取标题:

val maximumFrameLength = 1024 * 1024

val endOfMessageLine : () => Byte => Boolean = () => {
  var previousWasCarriage = false

  (byte) => 
    if(byte == '\r') {
      previousWasCarriage = true
      false
    }
    else if(byte == '\n' && previousWasCarriage) {
      previousWasCarriage = false
      true
    }
    else {
      previousWasCarriage = false
      false
    }
}

def subFlow = 
  Flow[ByteString].flatMapConcat(str => Source.fromIterable(str))
                  .splitAfter(endOfMessageLine())

不幸的是,这可能要求您的请求也通过Tcp绑定作为原始ByteString发送。

© www.soinside.com 2019 - 2024. All rights reserved.