【问题标题】:Spray client - treat response with unexpected content-type as application/json?喷雾客户端 - 将具有意外内容类型的响应视为应用程序/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 在解组时忽略这一点?

【问题讨论】:

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


    【解决方案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"))
    

    【讨论】:

    • 这只有在制作人关心你的要求时才会起作用。就我而言,它没有。
    • 我认为你误读了我的帖子。我和你做同样的事情(在收到响应后设置内容类型),只是代码更简洁一些。微小的改进,没有什么激进的。
    猜你喜欢
    • 2013-05-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多