WebExceptionHandlerを追加して、APIの例外を処理したいのですが。ステータスコードは変更できますが、応答の本文を変更したいときは行き詰まります。たとえば、例外メッセージやカスタムオブジェクトを追加します。
誰かに例がありますか?
WebExceptionHandlerを追加する方法:
HttpHandler httpHandler = WebHttpHandlerBuilder.webHandler(toHttpHandler(routerFunction))
.prependExceptionHandler((serverWebExchange, exception) -> {
exchange.getResponse().setStatusCode(myStatusGivenTheException);
exchange.getResponse().writeAndFlushWith(??)
return Mono.empty();
}).build();
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));
}
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()
}
}
答えを考えると、オブジェクトをシリアル化するには、次のように使用します。
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);
[〜#〜] 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%確実ではありませんが、いくつかの意見を得たいと思います。