web-dev-qa-db-ja.com

WebExceptionHandler:Spring Webfluxで本体を記述する方法

WebExceptionHandlerを追加して、APIの例外を処理したいのですが。ステータスコードは変更できますが、応答の本文を変更したいときは行き詰まります。たとえば、例外メッセージやカスタムオブジェクトを追加します。

誰かに例がありますか?

WebExceptionHandlerを追加する方法:

HttpHandler httpHandler = WebHttpHandlerBuilder.webHandler(toHttpHandler(routerFunction))
  .prependExceptionHandler((serverWebExchange, exception) -> {

      exchange.getResponse().setStatusCode(myStatusGivenTheException);
      exchange.getResponse().writeAndFlushWith(??)
      return Mono.empty();

  }).build();
11
adrien le roy

WebExceptionHandlerはかなり低レベルなので、リクエスト/レスポンス交換を直接処理する必要があります。

ご了承ください:

  • Mono<Void>戻り値の型は、応答処理の終わりを示す必要があります。これがPublisherに接続して応答を書き込む必要がある理由です
  • このレベルでは、データバッファーを直接処理しています(利用できるシリアル化サポートはありません)。

WebExceptionHandlerは次のようになります。

(serverWebExchange, exception) -> {

  exchange.getResponse().setStatusCode(myStatusGivenTheException);
  byte[] bytes = "Some text".getBytes(StandardCharsets.UTF_8);
  DataBuffer buffer = exchange.getResponse().bufferFactory().wrap(bytes);
  return exchange.getResponse().writeWith(Flux.just(buffer));
}
7
Brian Clozel

ServerResponseにはメソッドwriteToがあり、これを使用してServerExchangeにボディを書き込むことができます(Springフレームワークはこの方法を使用します)。問題は、2番目のパラメーターとしてContextを指定する必要があることだけなので、フレームワークの実装からHandlerStrategiesResponseContextをコピーしたところです。

WebExceptionHandlerの使用中にこのバージョンRouterFunctionsが登録されなかった前に、少なくともSpring Boot 2.0.0 M2を使用していることを確認してください。

import org.springframework.http.HttpStatus
import org.springframework.http.HttpStatus.*
import org.springframework.http.codec.HttpMessageWriter
import org.springframework.stereotype.Component
import org.springframework.web.reactive.function.server.HandlerStrategies
import org.springframework.web.reactive.function.server.ServerResponse
import org.springframework.web.reactive.result.view.ViewResolver
import org.springframework.web.server.ServerWebExchange
import org.springframework.web.server.WebExceptionHandler


@Component
class GlobalErrorHandler() : WebExceptionHandler {

    override fun handle(exchange: ServerWebExchange, ex: Throwable): Mono<Void> =
        handle(ex)
                .flatMap {
                    it.writeTo(exchange, HandlerStrategiesResponseContext(HandlerStrategies.withDefaults()))
                }
                .flatMap {
                    Mono.empty<Void>()
                }

    fun handle(throwable: Throwable): Mono<ServerResponse> {

        return when (throwable) {
            is EntityNotFoundException -> {
                createResponse(NOT_FOUND, "NOT_FOUND", "Entity not found, details: ${throwable.message}")
            }
            else -> {
                createResponse(INTERNAL_SERVER_ERROR, "GENERIC_ERROR", "Unhandled exception")
            }
        }
    }

    fun createResponse(httpStatus: HttpStatus, code: String, message: String): Mono<ServerResponse> =
        ServerResponse.status(httpStatus).syncBody(ApiError(code, message))
}

private class HandlerStrategiesResponseContext(val strategies: HandlerStrategies) : ServerResponse.Context {

    override fun messageWriters(): List<HttpMessageWriter<*>> {
        return this.strategies.messageWriters()
    }

    override fun viewResolvers(): List<ViewResolver> {
        return this.strategies.viewResolvers()
    }
}
4

答えを考えると、オブジェクトをシリアル化するには、次のように使用します。

 Mono<DataBuffer> db = commonsException.getErrorsResponse().map(errorsResponse -> {

     ObjectMapper objectMapper = new ObjectMapper();
     try {
         return objectMapper.writeValueAsBytes(errorsResponse);
     } catch (JsonProcessingException e) {
          return e.getMessage().getBytes();
     }
}).map(s -> exchange.getResponse().bufferFactory().wrap(s));

exchange.getResponse().getHeaders().add("Content-Type", "application/json");
exchange.getResponse().setStatusCode(commonsException.getHttpStatus());
return exchange.getResponse().writeWith(db);
2
adrien le roy

[〜#〜] json [〜#〜]レスポンスボディを記述する方法を探している人のために、Kotlinコードサンプルを次に示します。

fun writeBodyJson(body: Any, exchange: ServerWebExchange) =
    exchange.response.writeWith(
        Jackson2JsonEncoder().encode(
            Mono.just(body),
            exchange.response.bufferFactory(),
            ResolvableType.forInstance(body),
            MediaType.APPLICATION_JSON_UTF8,
            Hints.from(Hints.LOG_PREFIX_HINT, exchange.logPrefix))
    )

100%確実ではありませんが、いくつかの意見を得たいと思います。

0
Hartmut