【发布时间】:2017-12-07 10:02:09
【问题描述】:
我的应用支持 protobuf 和 JSON 序列化。对于 JSON 序列化,我使用 com.trueaccord.scalapb.json.JsonFormat,我的 dto 是从 proto 定义生成的。
com.trueaccord 序列化程序将选项类型包装到 JSON 对象中,这会导致某些客户端出现问题,因此我希望能够支持 org.json4s 而不会破坏现有客户端。
我希望能够选择基于名为 JFORMAT 的自定义 http 标头的序列化程序。这个想法是,如果发送此标头,我将使用 json4s,否则我将使用 trueaccord 序列化程序。
我设法创建了一个 Unmarshaller,它可以根据标头值选择一个请求序列化器:
Unmarshaller.withMaterializer[HttpRequest, T](_ => implicit mat => {
case request: HttpRequest =>
val entity = request.entity
entity.dataBytes.runFold(ByteString.empty)(_ ++ _).map(data => {
entity.contentType match {
case `applicationJsonContentType` =>
val jsFormat = {
val header = request.headers.find(h => h.name() == jsonFormatHeaderName)
if (header.isEmpty) "1.0" else header.get.value()
}
val charBuffer = Unmarshaller.bestUnmarshallingCharsetFor(entity)
val jsonText = data.decodeString(charBuffer.nioCharset().name())
val dto = if(jsFormat == "2.0") {
write[T](value)(formats) // New Formatter
} else {
JsonFormat.fromJsonString[T](jsonText) // Old Formatter
}
dto
case `protobufContentType` =>
companion.parseFrom(CodedInputStream.newInstance(data.asByteBuffer)) // Proto Formatter
case _ =>
throw UnsupportedContentTypeException(applicationJsonContentType, protobufContentType)
}
})
我想对我与 Marshaller.oneOf 一起使用的 Marshaller 做同样的事情,JSON 处理看起来像:
Marshaller.withFixedContentType(contentType) { value =>
val jsonText = JsonSerializer.toJsonString[T](value)
HttpEntity(contentType, jsonText)
}
有没有办法构造一个知道请求 http 标头的 Mashaller? Akka HTTP 文档没有任何示例,我无法理解 PredefinedToRequestMarshallers。
我是否需要以某种方式组合多个编组器,或者我可以在请求序列化期间将一些元数据附加到上下文中,以便稍后在编组器中使用?如果可能,我想避免将 meta 附加到我的 dto 或使用自定义内容类型,如 application/vnd.api+json
当我格式化响应(例如 Accept-Encoding)时,我可以从请求中使用许多其他有用的信息,自定义标头(例如唯一请求 ID 以创建关联 ID),我可以通过阅读 callback 查询来添加 JSONP 支持参数等。
澄清一下:我需要一个解决方案来使用 Mashaller、它的子类或由工厂方法创建的自定义版本,或者可能是多个链接在一起的 Marshaller。 Marshaller.withFixedContentType 已经在使用 Accept 标头,所以必须有办法。我添加了额外的赏金来奖励特定挑战的解决方案。我知道黑客和解决方法,我问了这个问题,因为我需要一个干净的解决方案来解决特定的场景。
【问题讨论】:
-
我可能在这里遗漏了一些东西:为什么不在收到请求后实例化你的编组器,并且一旦你知道你需要哪一个?对管理所有内容类型进行解组是有意义的,但是编组几乎就是您将答案转换为您想要的任何内容,因此如果您希望它依赖于请求,请将其作为请求的函数?
标签: json scala marshalling unmarshalling akka-http