ktor 接收 json 正文两次

问题描述 投票:0回答:2

我无法两次接收 ktor HttpClient 的 json 正文。 对于服务器,有一个 DoubleReceive 功能,但我不知道在进行客户端调用时如何使用它。

我想调用一个不同的微服务,它要么返回一些 json,要么当出现错误时返回,例如状态 500 和错误描述 json 负载。

所以我尝试了 HttpResponseValidator ,并且只允许使用此代码进行 readBytes

HttpResponseValidator {
validateResponse { response ->
  val statusCode = response.status.value
  val originCall = response.call

  if (statusCode < 300 || originCall.attributes.contains(ValidateMark)) return@validateResponse
  response.use {
    val exceptionCall = originCall.save().apply {
      attributes.put(ValidateMark, Unit)
    }
    //try parse error from json payload which other microservice usually send
    exceptionCall.response.receiveError()?.also { throw mapErrors(response, it) }
    //default ktor exception mapping
    when (statusCode) {
      in 300..399 -> throw RedirectResponseException(response)
      in 400..499 -> throw ClientRequestException(response)
      in 500..599 -> throw ServerResponseException(response)
    }
    if (statusCode >= 600) {
      throw ResponseException(response)
    }
  }
}

}

receiveError 可以用作

JacksonConfig.defaultMapper.readValue<ServiceErrorResponse>(this.readBytes())
但如果你只是调用
response.receive<ServiceErrorResponse>()
则会抛出 DoubleReceivException 原因是接收函数首先检查
received atomicBoolean

TL;博士 现在我想知道是否有关于如何处理错误有效负载的任何想法,或者您只是不使用它们?我对这种方式的微服务很陌生,因此需要添加它们。 Ktor 是一个新成员。如何在服务之间传递错误信息?

还有一种方法可以在客户端使用 DoubleReceive 功能。因为

HttpClient(){install(DoubleReceive)}
不起作用,因为它不是 ApplicationFeature 也不是 ClientFeature。

exception microservices ktor
2个回答
0
投票

Ktor 开发了一个名为 Double Receive 的实验性插件,您可以使用它来接收任意数量的请求体。

了解更多:https://ktor.io/docs/double-receive.html


0
投票

尝试制作自定义插件。看来这个解决方案可以提供帮助。至少对我有用。

自定义重试插件.kt

internal class CustomRetryPluginConfig {
    var retries = 2

    internal var modifyRequest: suspend (builder: HttpRequestBuilder) -> Unit = {}

    internal var retryIf: suspend (httpResponse: HttpResponse) -> Boolean = { false }

    fun shouldRetry(block: suspend (httpResponse: HttpResponse) -> Boolean) {
        retryIf = block
    }

    fun modifyRequest(block: suspend (builder: HttpRequestBuilder) -> Unit) {
        modifyRequest = block
    }
}

internal val CustomRetryPlugin = createClientPlugin("RetryPlugin", ::CustomRetryPluginConfig) {

    val retries = pluginConfig.retries
    val modifyRequest = pluginConfig.modifyRequest
    val shouldRetry = pluginConfig.retryIf

    on(Send) { request ->
        var originalCall = proceed(request)

        var tryCount = retries
        while (tryCount > 0) {
            originalCall.response.run {
                val savedCall = originalCall.save()
                val response = savedCall.response
                if (shouldRetry(response)) {
                    modifyRequest(request)
                    tryCount -= 1
                    originalCall = proceed(request)
                } else {
                    tryCount = 0
                    originalCall = savedCall
                }
            }
        }
        originalCall
    }
}

用途:

install(CustomRetryPlugin) {
            shouldRetry { response ->
                // make any checks for error inside body
            }

            modifyRequest { builder ->
                // modify any new headers or params
            }
        }

© www.soinside.com 2019 - 2024. All rights reserved.