springboot webflux/gateway 异常处理

相关类

WebExceptionHandler

/**
 * Contract for handling exceptions during web server exchange processing.
 */
public interface WebExceptionHandler {

	/**
	 * 
	 */
	Mono<Void> handle(ServerWebExchange exchange, Throwable ex);
}

ErrorWebExceptionHandler

@FunctionalInterface
public interface ErrorWebExceptionHandler extends WebExceptionHandler {

}

自定义全局异常处理

GlobalExceptionHandler

@Component
@Slf4j
public class GlobalExceptionHandler implements ErrorWebExceptionHandler {
	// 打印日志时使用
    private static final String ERROR_STACKTRACE = "Stacktrace:";
    // 异常返回的状态码
    private static final String KEY_STATUS = "httpStatus";
    // 异常返回信息主体
    private static final String KEY_BODY = "body";
    private Tracer tracer;

    public void setTracer(Tracer tracer) {
        this.tracer = tracer;
    }

    private final ObjectMapper objectMapper = new ObjectMapper();
    /**
     * MessageReader
     */
    private List<HttpMessageReader<?>> messageReaders = Collections.emptyList();

    /**
     * MessageWriter
     */
    private List<HttpMessageWriter<?>> messageWriters = Collections.emptyList();

    /**
     * ViewResolvers
     */
    private List<ViewResolver> viewResolvers = Collections.emptyList();

    /**
     * 存储处理异常后的信息
     */
    private final ThreadLocal<Map<String, Object>> exceptionHandlerResult = new ThreadLocal<>();

    /**
     * 参考AbstractErrorWebExceptionHandler
     */
    public void setMessageReaders(List<HttpMessageReader<?>> messageReaders) {
        Assert.notNull(messageReaders, "'messageReaders' must not be null");
        this.messageReaders = messageReaders;
    }

    /**
     * 参考AbstractErrorWebExceptionHandler
     */
    public void setViewResolvers(List<ViewResolver> viewResolvers) {
        this.viewResolvers = viewResolvers;
    }

    /**
     * 参考AbstractErrorWebExceptionHandler
     */
    public void setMessageWriters(List<HttpMessageWriter<?>> messageWriters) {
        Assert.notNull(messageWriters, "'messageWriters' must not be null");
        this.messageWriters = messageWriters;
    }

    /**
     * 全局异常处理器 根据需求自定义
     *
     * @param serverWebExchange exchange
     * @param throwable         throwable
     * @return void
     */
    @SneakyThrows
    @Override
    public Mono<Void> handle(ServerWebExchange serverWebExchange, Throwable throwable) {
        // 按照异常类型进行处理
        Map<String, Object> result = new HashMap<>(2, 1);
        ServerHttpRequest request = serverWebExchange.getRequest();
        // 异常处理 此处添加自定义异常处理
        if (throwable instanceof ResponseStatusException) {
            ResponseStatusException exception = (ResponseStatusException) throwable;
            CustomExceptionResponse customExceptionResponse =
                    new CustomExceptionResponse(String.valueOf(exception.getRawStatusCode()),
                            exception.getReason(),request.getURI().getPath());
            log.debug("ResponseStatusException occurred, url: {}", request.getURI().getPath());
            log.debug(ERROR_STACKTRACE, exception);
            String body = objectMapper.writeValueAsString(customExceptionResponse);
            result.put(KEY_STATUS, exception.getStatus());
            result.put(KEY_BODY, body);
        } else {
            log.error("Exception occurred, url: {}", request.getURI().getPath());
            log.error(ERROR_STACKTRACE, throwable);
            CustomExceptionResponse customExceptionResponse =
                    new CustomExceptionResponse(null,throwable.getMessage(),
                    	request.getURI().getPath());
            String body = objectMapper.writeValueAsString(customExceptionResponse);
            result.put(KEY_STATUS, HttpStatus.INTERNAL_SERVER_ERROR);
            result.put(KEY_BODY, body);
        }
        //参考AbstractErrorWebExceptionHandler
        if (serverWebExchange.getResponse().isCommitted()) {
            return Mono.error(throwable);
        }
        exceptionHandlerResult.set(result);
        ServerRequest newRequest = ServerRequest.create(serverWebExchange, this.messageReaders);
        Span span = tracer.currentSpan();
        if (span != null) {
            span.tag("exception", throwable.toString());
            span.flush();
        }
        return RouterFunctions.route(RequestPredicates.all(), this::renderErrorResponse).route(newRequest)
                .switchIfEmpty(Mono.error(throwable))
                .flatMap((handler) -> handler.handle(newRequest))
                .flatMap((response) -> write(serverWebExchange, response));

    }

    /**
     * 参考DefaultErrorWebExceptionHandler
     */
    protected Mono<ServerResponse> renderErrorResponse(ServerRequest request) {
        Map<String, Object> result = exceptionHandlerResult.get();
        return ServerResponse.status((HttpStatus) result.get(KEY_STATUS))
                .contentType(MediaType.APPLICATION_JSON)
                .body(BodyInserters.fromValue(result.get(KEY_BODY)));
    }

    /**
     * 参考AbstractErrorWebExceptionHandler
     */
    private Mono<? extends Void> write(ServerWebExchange exchange,
                                       ServerResponse response) {
        exchange.getResponse().getHeaders()
                .setContentType(response.headers().getContentType());
        return response.writeTo(exchange, new ResponseContext());
    }

    /**
     * 参考AbstractErrorWebExceptionHandler
     */
    private class ResponseContext implements ServerResponse.Context {


        @Override
        public List<HttpMessageWriter<?>> messageWriters() {
            return GlobalExceptionHandler.this.messageWriters;
        }

        @Override
        public List<ViewResolver> viewResolvers() {
            return GlobalExceptionHandler.this.viewResolvers;
        }

    }
}

CustomExceptionResponse :

/**
 * 错误返回的类型
 */
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class CustomExceptionResponse {
    private String errorCode;
    private String message;
    private String path;
}

ExceptionConfig:

/**
 * 异常配置
 */
@Configuration
public class ExceptionConfig {
    /**
     * 自定义异常处理[@@]注册Bean时依赖的Bean,会从容器中直接获取,所以直接注入即可
     */
    @Primary
    @Bean
    @Order(Ordered.HIGHEST_PRECEDENCE)
    public ErrorWebExceptionHandler errorWebExceptionHandler(ObjectProvider<List<ViewResolver>> viewResolversProvider,
                                                             ServerCodecConfigurer serverCodecConfigurer,
                                                             Tracer tracer) {
        GlobalExceptionHandler globalExceptionHandler = new GlobalExceptionHandler();
        globalExceptionHandler.setTracer(tracer);
        globalExceptionHandler.setViewResolvers(viewResolversProvider.getIfAvailable(Collections::emptyList));
        globalExceptionHandler.setMessageWriters(serverCodecConfigurer.getWriters());
        globalExceptionHandler.setMessageReaders(serverCodecConfigurer.getReaders());
        return globalExceptionHandler;
    }
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值