Akka Streams/HTTP:如何从HttpResponse获取原始HttpRequest或保留原信息?
问题解答
很遗憾,你没办法直接从HttpResponse中获取对应的原始HttpRequest。Akka HTTP的outgoingConnection返回的Flow只负责传递请求后的响应结果,并不会自动关联请求时的原始信息。
不过有几种简单可靠的方法可以帮你保留需要的原始请求信息,下面是最常用的两种方案:
1. 用元组/自定义类打包上下文与请求
核心思路是在发送请求前,把需要保留的原始信息(比如你的输入字符串,或者HttpRequest里的关键字段)和请求对象打包在一起,等拿到响应后再将两者关联起来,这样就能在toMessage中使用原始信息了。
如果用singleRequest(更适合大多数短连接场景),代码可以这样写:
source // 把原始字符串和转换后的HttpRequest打包成元组 .map(rawString => (rawString, toRequest(rawString))) // 并发发送请求,同时保留上下文 .mapAsync(parallelism = 4) { case (rawData, request) => Http().singleRequest(request).map(response => (rawData, response)) } // 现在可以同时拿到原始数据和响应,构造下游需要的消息 .map { case (rawData, response) => toMessage(response, rawData) }
如果你坚持要用outgoingConnection(长连接场景),可以通过自定义Flow来实现上下文关联:
import akka.stream.scaladsl.{Flow, GraphDSL, Zip} import akka.stream.{FlowShape, GraphDSL} // 构建一个能保留上下文的Flow def flowWithContext[T](host: String): Flow[(T, HttpRequest), (T, HttpResponse), _] = Flow.fromGraph(GraphDSL.create() { implicit builder => import GraphDSL.Implicits._ // 拆分上下文和请求 val splitCtx = builder.add(Flow[(T, HttpRequest)].map(_._1)) val splitReq = builder.add(Flow[(T, HttpRequest)].map(_._2)) // Akka HTTP的长连接Flow val httpFlow = builder.add(Http().outgoingConnection(host)) // 将上下文和响应重新打包 val zip = builder.add(Zip[T, HttpResponse]()) splitReq ~> httpFlow ~> zip.in1 splitCtx ~> zip.in0 FlowShape(splitReq.in, zip.out) }) // 使用这个Flow source .map(rawString => (rawString, toRequest(rawString))) .via(flowWithContext(host)) .map { case (rawData, response) => toMessage(response, rawData) }
2. 自定义消息携带上下文(更优雅的方式)
如果元组不够灵活,你可以定义一个专门的包装类来携带上下文和请求,比如:
case class RequestWithContext(rawData: String, request: HttpRequest) case class ResponseWithContext(rawData: String, response: HttpResponse) // 然后用这个类来处理流 source .map(raw => RequestWithContext(raw, toRequest(raw))) .mapAsync(4) { ctxReq => Http().singleRequest(ctxReq.request).map(resp => ResponseWithContext(ctxReq.rawData, resp)) } .map(ctxResp => toMessage(ctxResp.response, ctxResp.rawData))
这种方式代码可读性更高,尤其是当你需要保留的上下文信息较多时。
内容的提问来源于stack exchange,提问作者gkatzioura
相关产品推荐
相关产品推荐

