喷涂客户端 - 将具有意外内容类型的响应视为application / json?

时间:2014-06-30 12:00:31

标签: scala playframework-2.0 spray spray-json spray-client

当我尝试获取像这样的亚马逊身份数据时

val pipeline: HttpRequest => Future[IdentityData] = sendReceive ~> unmarshal[IdentityData]
pipeline(Get("http://169.254.169.254/latest/dynamic/instance-identity/document"))

使用适当的case类和formatter,我收到以下异常

UnsupportedContentType(预期' application / json')

因为亚马逊将其回复标记为 text / plain 内容类型。他们也不关心 Accept 标题参数。是否有一种简单的方法可以告诉spray-json在解组时忽略它?

3 个答案:

答案 0 :(得分:5)

在挖掘邮件列表后,我写了一个有效的功能

def mapTextPlainToApplicationJson: HttpResponse => HttpResponse = {
  case r@ HttpResponse(_, entity, _, _) =>
    r.withEntity(entity.flatMap(amazonEntity => HttpEntity(ContentType(MediaTypes.`application/json`), amazonEntity.data)))
  case x => x
}

并在管道中使用它

val pipeline: HttpRequest => Future[IdentityData] = sendReceive ~> mapTextPlainToApplicationJson ~> unmarshal[IdentityData]
pipeline(Get("http://169.254.169.254/latest/dynamic/instance-identity/document"))

很酷的事情就是在这里你可以拦截&只要您的拦截功能具有适当的签名,就可以更改任何 HttpResponse

答案 1 :(得分:3)

如果你想从亚马逊响应中提取一些IdentityData(这是一个定义为jsonFormat的案例类),这是一个有效的json,但是你可以使用text/plain上下文类型只需提取文本数据,将其解析为json并转换为您的数据,例如:

entity.asString.parseJson.convertTo(identityDataJsonFormat)

答案 2 :(得分:1)

我想出了一个更简单/更清洁的@ yevgeniy-mordovkin解决方案。

def setContentType(mediaType: MediaType)(r: HttpResponse): HttpResponse = {
  r.withEntity(HttpEntity(ContentType(mediaType), r.entity.data))
}

用法:

val pipeline: HttpRequest => Future[IdentityData] = (
       sendReceive
    ~> setContentType(MediaTypes.`application/json`)
    ~> unmarshal[IdentityData]
)
pipeline(Get("http://169.254.169.254/latest/dynamic/instance-identity/document"))