Akka http流式传输响应标头

时间:2018-08-29 11:20:43

标签: akka akka-stream akka-http

根据定义,http响应分为3 partsstatus-code -> headers -> body,并且在进行akka客户端时,http请求在完全完成前2个部分后收到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)

1 个答案:

答案 0 :(得分:1)

akka-http

不可用

representation of HttpResponse将标头视为Seq[HttpHeader],而不是Iteratorakka-stream Source。因此,如问题中所述,如果没有所有可用的标头值都首先可用,则无法实例化HttpResponse对象。

我不知道此设计决定背后的确切原因,但我怀疑这是因为很难为标头提供源,为正文提供源。如果不先使用标头Source,就无法使用主体Source,因此必须严格访问访问响应的成员变量。这会导致混乱和意外错误。

使用akka-stream

进行较低级别的处理

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

  

响应消息包含以下内容:

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

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

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发送。