15

我想通过添加 WebExceptionHandler 来处理我的 api 异常。我可以更改状态代码,但是当我想更改响应的主体时我被卡住了:例如添加异常消息或自定义对象。

有人有例子吗?

我如何添加我的 WebExceptionHandler :

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

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

  }).build();
4

4 回答 4

18

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));
}
于 2017-07-20T12:56:04.990 回答
5

给定答案,为了序列化我使用这种方式的对象:

 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);
于 2017-07-21T13:19:35.747 回答
4

ServerResponse有一个方法writeTo可以用来写你的身体ServerExchange(Spring框架就是这样做的)。唯一的问题是您必须提供Context第二个参数,所以我刚刚HandlerStrategiesResponseContext从框架实现中复制。

确保您至少使用 Spring Boot 2.0.0 M2,在WebExceptionHandler使用RouterFunctions.

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()
    }
}
于 2017-08-15T06:06:48.150 回答
2

对于任何想要编写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%确定这是要走的路,但想得到一些意见。

于 2018-07-30T07:52:02.547 回答