Scala Spray client-将具有意外内容类型的响应视为application/json?

Scala Spray client-将具有意外内容类型的响应视为application/json?,scala,playframework-2.0,spray,spray-json,spray-client,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类和格式化程序,我收到以下异常 不受支持的内容类型(应为“应用程序/json”) 因为am

当我试图获取亚马逊的身份数据时

val pipeline: HttpRequest => Future[IdentityData] = sendReceive ~> unmarshal[IdentityData]
pipeline(Get("http://169.254.169.254/latest/dynamic/instance-identity/document"))
使用适当的case类和格式化程序,我收到以下异常

不受支持的内容类型(应为“应用程序/json”)


因为amazon将其响应标记为文本/普通内容类型。它们也不关心Accept头参数。有没有一种简单的方法告诉spray json在解组时忽略这一点

在挖掘spray mail列表后,我编写了一个有效的函数

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。

如果您想从amazon响应中提取一些
IdentityData
(这是一个定义了
jsonFormat
)的case类,它是一个有效的json,但是使用
text/plain
上下文类型,您可以简单地提取文本数据,将其解析为json并转换为您的数据,例如:

entity.asString.parseJson.convertTo(identityDataJsonFormat)

我提出了一个更简单/更干净的@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"))

没想到这么简单。感谢您提醒我们检查简单选项:-)在经历了数小时的挫折之后,这真的很有帮助。谢谢!无需编写函数,有
mapHttpResponseEntity
方向,也无需在HttpResponse实体上匹配
,并将
应用于entity
,因为它将检查您的实体参数,如果它不同(包括空实体大小写),则应用它,因此您只需使用entity(..)执行
此解决方案很好,但可以通过确保保留原始响应的
ContentType
中的
HttpCharset
来改进。将新的内容类型值设置为
ContentType(MediaTypes.`applicationon/json`,amazonEntity.ContentType.charset)
只有当制作人关心您的要求时,这才有效。对我来说不是。我想你误读了我的帖子。我和您做了同样的事情(在收到响应后设置内容类型),只是代码稍微干净一点。小的改进,没有什么激进的。