`transformWith[Array[Byte]]` 中的 `Future.failed` 给出编译器错误
`Future.failed` inside of `transformWith[Array[Byte]]` gives a compiler error
我正在尝试分析来自 Akka 的 HttpResponse
。理想的行为是,如果响应成功返回,则传递 HttpEntity
的 Array[Byte]
表示进行处理。但是,如果状态返回失败,则传递一个 Future.failed
异常,其中包含状态代码和 HttpEntity
的 JSON 树表示。传递 JSON 树的原因是有不同的服务器被这个抽象请求方法命中,并且它们的响应格式不同,所以我想在其他 [=41= 中处理响应的解析].
我已尝试对这个工作流进行多种操作。直接抛出异常而不是 returning Future.failed
return 一个 None
值代替异常中的 JSON 树。其他方法产生类似的结果。当我 println(MAPPER.readTree(byteArray))
它按我的预期打印出响应,但随后在 BadRequestException
.[=26= 的 response
字段中继续 return None
]
import akka.http.scaladsl.model._
import akka.http.scaladsl.model.headers.Authorization
import akka.stream.Materializer
import com.fasterxml.jackson.databind.{DeserializationFeature, JsonNode, ObjectMapper}
import com.fasterxml.jackson.module.scala.DefaultScalaModule
import com.fasterxml.jackson.module.scala.experimental.ScalaObjectMapper
val MAPPER = new ObjectMapper with ScalaObjectMapper
MAPPER.registerModule(DefaultScalaModule)
MAPPER.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
def performQueryRaw(method: HttpMethod, uri: Uri, entity: Option[RequestEntity] = None, authorization: Option[Authorization] = None): Future[Array[Byte]] = {
val request: HttpRequest = HttpRequest(
method = method,
uri = uri,
entity = entity.getOrElse(HttpEntity.Empty),
headers = authorization.toList)
http.singleRequest(request).transformWith[Array[Byte]] {
case Success(response: HttpResponse) =>
convertEntityToBytes(response.entity).map { byteArray =>
if (response.status.isFailure()) Future.failed(BadRequestException(response.status, MAPPER.readTree(byteArray)))
else byteArray
}
case Failure(throwable) => Future.failed(RequestFailedException(throwable.getMessage + " -- " + uri.toString, throwable))
}
}
def convertEntityToBytes(entity: HttpEntity): Future[Array[Byte]] = {
entity.dataBytes.runFold[Seq[Array[Byte]]] (Nil) {
case (acc, next) => acc :+ next.toArray
}.map(_.flatten.toArray)
}
case class BadRequestException(status: StatusCode, response: JsonNode = None.orNull, t: Throwable = None.orNull) extends Exception(t)
case class RequestFailedException(message: String, t: Throwable = None.orNull) extends Exception(message, t)
我期待 JsonNode 的 BadRequestException
具有非 none 值。相反,我在 Future.failed
上收到编译器错误,内容为:
Expression of type Future[Nothing] doesn't conform to expected type Array[Byte]
.
如有任何帮助,我们将不胜感激。
当您 运行 在 convertEntityToBytes
之后进行下一步时,请使用 flatMap
而不是 map
:
def performQueryRaw(
method: HttpMethod,
uri: Uri,
entity: Option[RequestEntity] = None,
authorization: Option[Authorization] = None
): Future[Array[Byte]] = {
val request: HttpRequest = HttpRequest(
method = method,
uri = uri,
entity = entity.getOrElse(HttpEntity.Empty),
headers = authorization.toList
)
Http().singleRequest(request).transformWith[Array[Byte]] {
case Success(response: HttpResponse) =>
convertEntityToBytes(response.entity).flatMap { byteArray =>
if (response.status.isFailure()) Future.failed(new Exception("change this exception to one you had"))
else Future.successful(byteArray)
}
case Failure(throwable) => Future.failed(new Exception("also here"))
}
}
既然你想让你的Future
计算失败,你需要return新的Future
。万一失败,你已经在做Future.failed
了。缺少的部分也是将 byteArray 包装到 Future.successful
。当然,这是解决此代码中类型编译错误的方法之一。
我正在尝试分析来自 Akka 的 HttpResponse
。理想的行为是,如果响应成功返回,则传递 HttpEntity
的 Array[Byte]
表示进行处理。但是,如果状态返回失败,则传递一个 Future.failed
异常,其中包含状态代码和 HttpEntity
的 JSON 树表示。传递 JSON 树的原因是有不同的服务器被这个抽象请求方法命中,并且它们的响应格式不同,所以我想在其他 [=41= 中处理响应的解析].
我已尝试对这个工作流进行多种操作。直接抛出异常而不是 returning Future.failed
return 一个 None
值代替异常中的 JSON 树。其他方法产生类似的结果。当我 println(MAPPER.readTree(byteArray))
它按我的预期打印出响应,但随后在 BadRequestException
.[=26= 的 response
字段中继续 return None
]
import akka.http.scaladsl.model._
import akka.http.scaladsl.model.headers.Authorization
import akka.stream.Materializer
import com.fasterxml.jackson.databind.{DeserializationFeature, JsonNode, ObjectMapper}
import com.fasterxml.jackson.module.scala.DefaultScalaModule
import com.fasterxml.jackson.module.scala.experimental.ScalaObjectMapper
val MAPPER = new ObjectMapper with ScalaObjectMapper
MAPPER.registerModule(DefaultScalaModule)
MAPPER.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
def performQueryRaw(method: HttpMethod, uri: Uri, entity: Option[RequestEntity] = None, authorization: Option[Authorization] = None): Future[Array[Byte]] = {
val request: HttpRequest = HttpRequest(
method = method,
uri = uri,
entity = entity.getOrElse(HttpEntity.Empty),
headers = authorization.toList)
http.singleRequest(request).transformWith[Array[Byte]] {
case Success(response: HttpResponse) =>
convertEntityToBytes(response.entity).map { byteArray =>
if (response.status.isFailure()) Future.failed(BadRequestException(response.status, MAPPER.readTree(byteArray)))
else byteArray
}
case Failure(throwable) => Future.failed(RequestFailedException(throwable.getMessage + " -- " + uri.toString, throwable))
}
}
def convertEntityToBytes(entity: HttpEntity): Future[Array[Byte]] = {
entity.dataBytes.runFold[Seq[Array[Byte]]] (Nil) {
case (acc, next) => acc :+ next.toArray
}.map(_.flatten.toArray)
}
case class BadRequestException(status: StatusCode, response: JsonNode = None.orNull, t: Throwable = None.orNull) extends Exception(t)
case class RequestFailedException(message: String, t: Throwable = None.orNull) extends Exception(message, t)
我期待 JsonNode 的 BadRequestException
具有非 none 值。相反,我在 Future.failed
上收到编译器错误,内容为:
Expression of type Future[Nothing] doesn't conform to expected type Array[Byte]
.
如有任何帮助,我们将不胜感激。
当您 运行 在 convertEntityToBytes
之后进行下一步时,请使用 flatMap
而不是 map
:
def performQueryRaw(
method: HttpMethod,
uri: Uri,
entity: Option[RequestEntity] = None,
authorization: Option[Authorization] = None
): Future[Array[Byte]] = {
val request: HttpRequest = HttpRequest(
method = method,
uri = uri,
entity = entity.getOrElse(HttpEntity.Empty),
headers = authorization.toList
)
Http().singleRequest(request).transformWith[Array[Byte]] {
case Success(response: HttpResponse) =>
convertEntityToBytes(response.entity).flatMap { byteArray =>
if (response.status.isFailure()) Future.failed(new Exception("change this exception to one you had"))
else Future.successful(byteArray)
}
case Failure(throwable) => Future.failed(new Exception("also here"))
}
}
既然你想让你的Future
计算失败,你需要return新的Future
。万一失败,你已经在做Future.failed
了。缺少的部分也是将 byteArray 包装到 Future.successful
。当然,这是解决此代码中类型编译错误的方法之一。