spring cloud gateway 格式化异常输出

/**
 * 自定义异常处理
 * 解决问题:
 * 1 统一网关响应消息格式"{\"status\":" + httpStatus + ",\"message\": \"" + message + "\"}"
 * 2 特殊异常处理,不让其直接抛往前端,比如feign调用过程,某些服务不可用“syscall:getsockopt(..) failed: 拒绝连接: /******:11340”
 *
 * @author tums
 * @date 2018/12/3 21:04
 */
public class JsonExceptionHandler implements ErrorWebExceptionHandler {
    private Logger logger = LoggerFactory.getLogger(JsonExceptionHandler.class);
    /**
     * MessageReader
     */
    private List> messageReaders = Collections.emptyList();

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

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

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

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

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

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

    @Override
    public Mono handle(ServerWebExchange exchange, Throwable ex) {
        // 按照异常类型进行处理
        HttpStatus httpStatus;
        String message;
        if (ex instanceof NotFoundException) {
            httpStatus = HttpStatus.NOT_FOUND;
            message = "Service Not Found";
        } else if (ex instanceof TokenExpiredException) {
            ResponseStatusException responseStatusException = (ResponseStatusException) ex;
            httpStatus = responseStatusException.getStatus();
            message = responseStatusException.getReason();
        } else if (ex instanceof ResponseStatusException) {
            ResponseStatusException responseStatusException = (ResponseStatusException) ex;
            httpStatus = responseStatusException.getStatus();
            message = responseStatusException.getMessage();
        } else {
            httpStatus = HttpStatus.INTERNAL_SERVER_ERROR;
            message = StringUtils.isEmpty(ex.getMessage()) ? "Internal Server Error" : ex.getMessage();
        }
        //封装响应体,此body可修改为自己的jsonBody
        Map result = new HashMap<>(2, 1);
        result.put("httpStatus", httpStatus);
        String msg = "{\"status\":" + httpStatus + ",\"message\": \"" + message + "\"}";
        result.put("body", msg);
        if (exchange.getResponse().isCommitted()) {
            return Mono.error(ex);
        }
        exceptionHandlerResult.set(result);
        ServerRequest newRequest = ServerRequest.create(exchange, this.messageReaders);
        return RouterFunctions.route(RequestPredicates.all(), this::renderErrorResponse).route(newRequest)
                .switchIfEmpty(Mono.error(ex))
                .flatMap((handler) -> handler.handle(newRequest))
                .flatMap((response) -> write(exchange, response));

    }

    /**
     * 参考DefaultErrorWebExceptionHandler
     * 

* 屏蔽特殊异常:{"status":500,"message": "syscall:getsockopt(..) failed: 拒绝连接: /******:11340"} */ private final static String GET_SOCKOPT_FAILED = "syscall:getsockopt(..) failed"; protected Mono renderErrorResponse(ServerRequest request) { Map result = exceptionHandlerResult.get(); HttpStatus httpStatus = (HttpStatus) result.get("httpStatus"); String body = (String) result.get("body"); if (httpStatus == HttpStatus.INTERNAL_SERVER_ERROR) { logger.error("path = {},body = {}", request.path(), body); if (body.contains(GET_SOCKOPT_FAILED)) { body = "{\"status\":" + httpStatus + ",\"message\": \"系统繁忙,请稍后重试\"}"; } } return ServerResponse.status(httpStatus) .contentType(MediaType.APPLICATION_JSON_UTF8) .body(BodyInserters.fromObject(body)); } /** * 参考AbstractErrorWebExceptionHandler */ private Mono 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> messageWriters() { return JsonExceptionHandler.this.messageWriters; } @Override public List viewResolvers() { return JsonExceptionHandler.this.viewResolvers; } } }

 

你可能感兴趣的:(spring,cloud)