喷雾客户端 - 将具有意外内容类型的响应视为应用程序/json?

Posted

技术标签:

【中文标题】喷雾客户端 - 将具有意外内容类型的响应视为应用程序/json?【英文标题】:Spray client - treat response with unexpected content-type as application/json? 【发布时间】:2014-08-20 19:09:36 【问题描述】:

当我尝试获取类似的亚马逊身份数据时

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

使用适当的案例类和格式化程序,我收到以下异常

UnsupportedContentType(预期为“应用程序/json”)

因为亚马逊将他们的响应标记为 text/plain 内容类型。他们也不关心 Accept 标头参数。有没有一种简单的方法可以告诉 spray-json 在解组时忽略这一点?

【问题讨论】:

【参考方案1】:

在挖掘了喷雾邮件列表后,我写了一个有效的函数

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

【讨论】:

你的函数不用写,有mapHttpResponseEntity指令 而且也不需要在HttpResponse实体上匹配并应用withEntity,因为它会检查你的实体arg并在它不同时应用它(包括空实体案例),所以你可以简单做_.withEntity(..) 这个解决方案很好,但可以通过确保保留原始响应的HttpCharset 中的ContentType 来改进。将新的内容类型值设置为ContentType(MediaTypes.`applicaiton/json`, amazonEntity.contentType.charset)【参考方案2】:

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

entity.asString.parseJson.convertTo(identityDataJsonFormat)

【讨论】:

没想到这么简单。感谢您提醒检查简单选项:-) 经过数小时的挫折,这确实很有帮助。非常感谢!【参考方案3】:

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

【讨论】:

这只有在制作人关心你的要求时才会起作用。就我而言,它没有。 我认为你误读了我的帖子。我和你做同样的事情(在收到响应后设置内容类型),只是代码更简洁一些。微小的改进,没有什么激进的。

以上是关于喷雾客户端 - 将具有意外内容类型的响应视为应用程序/json?的主要内容,如果未能解决你的问题,请参考以下文章

OpenSSL将内容类型为“应用程序/ EDI”的smime消息视为文本并更改换行符

仅在喷雾 json 中具有案例对象自定义实现的特征

远程服务器返回意外响应:(413) 请求实体太大。

夏天必备的防晒喷雾,重点是这个喷雾可以直接带上飞机

webSocket 握手期间的错误意外响应代码:400

WCF:具有不同内容类型的请求/响应