根据定义,http响应分为3 parts,status-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)
答案 0 :(得分:1)
akka-http
representation of HttpResponse
将标头视为Seq[HttpHeader]
,而不是Iterator
或akka-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发送。