• Java网关的统一异常处理


    使用网关时,往往会出现一些异常情况,导致没办法请求到真实的URL路径,所以在发生异常时,最好使用一个统一异常处理,返回一些友好的信息。

    我使用的是SpringCloud-Gateway网关

    统一异常处理步骤:

    1. 添加异常配置类

    1. import com.example.itvgetway.exception.CustomWebExceptionHandler;
    2. import org.springframework.beans.factory.ObjectProvider;
    3. import org.springframework.boot.web.reactive.error.ErrorWebExceptionHandler;
    4. import org.springframework.context.annotation.Bean;
    5. import org.springframework.context.annotation.Configuration;
    6. import org.springframework.context.annotation.Primary;
    7. import org.springframework.core.Ordered;
    8. import org.springframework.core.annotation.Order;
    9. import org.springframework.http.codec.ServerCodecConfigurer;
    10. import org.springframework.web.reactive.result.view.ViewResolver;
    11. import java.util.Collections;
    12. import java.util.List;
    13. @Configuration
    14. public class ExceptionConfig {
    15. /**
    16. * 自定义异常处理[@@]注册Bean时依赖的Bean,会从容器中直接获取,所以直接注入即可
    17. */
    18. @Primary
    19. @Bean
    20. @Order(Ordered.HIGHEST_PRECEDENCE)
    21. public ErrorWebExceptionHandler errorWebExceptionHandler(ObjectProvider> viewResolversProvider,
    22. ServerCodecConfigurer serverCodecConfigurer,
    23. CustomWebExceptionHandler customWebExceptionHandler) {
    24. customWebExceptionHandler.setViewResolvers(viewResolversProvider.getIfAvailable(Collections::emptyList));
    25. customWebExceptionHandler.setMessageWriters(serverCodecConfigurer.getWriters());
    26. customWebExceptionHandler.setMessageReaders(serverCodecConfigurer.getReaders());
    27. return customWebExceptionHandler;
    28. }
    29. }

    2. 编写异常处理器

    1. import com.example.itvgetway.util.ApiResult;
    2. import org.slf4j.Logger;
    3. import org.slf4j.LoggerFactory;
    4. import org.springframework.boot.web.reactive.error.ErrorWebExceptionHandler;
    5. import org.springframework.http.HttpStatus;
    6. import org.springframework.http.MediaType;
    7. import org.springframework.http.codec.HttpMessageReader;
    8. import org.springframework.http.codec.HttpMessageWriter;
    9. import org.springframework.http.server.reactive.ServerHttpRequest;
    10. import org.springframework.stereotype.Component;
    11. import org.springframework.util.Assert;
    12. import org.springframework.web.reactive.function.BodyInserters;
    13. import org.springframework.web.reactive.function.server.RequestPredicates;
    14. import org.springframework.web.reactive.function.server.RouterFunctions;
    15. import org.springframework.web.reactive.function.server.ServerRequest;
    16. import org.springframework.web.reactive.function.server.ServerResponse;
    17. import org.springframework.web.reactive.result.view.ViewResolver;
    18. import org.springframework.web.server.ResponseStatusException;
    19. import org.springframework.web.server.ServerWebExchange;
    20. import reactor.core.publisher.Mono;
    21. import java.util.Collections;
    22. import java.util.List;
    23. @Component
    24. public class CustomWebExceptionHandler implements ErrorWebExceptionHandler {
    25. private static final Logger log = LoggerFactory.getLogger(CustomWebExceptionHandler.class);
    26. /**
    27. * MessageReader
    28. */
    29. private List> messageReaders = Collections.emptyList();
    30. /**
    31. * MessageWriter
    32. */
    33. private List> messageWriters = Collections.emptyList();
    34. /**
    35. * ViewResolvers
    36. */
    37. private List viewResolvers = Collections.emptyList();
    38. /**
    39. * 存储处理异常后的信息
    40. */
    41. private ThreadLocal exceptionHandlerResult = new ThreadLocal<>();
    42. /**
    43. * 参考AbstractErrorWebExceptionHandler
    44. */
    45. public void setMessageReaders(List> messageReaders) {
    46. Assert.notNull(messageReaders, "'messageReaders' must not be null");
    47. this.messageReaders = messageReaders;
    48. }
    49. /**
    50. * 参考AbstractErrorWebExceptionHandler
    51. */
    52. public void setViewResolvers(List viewResolvers) {
    53. this.viewResolvers = viewResolvers;
    54. }
    55. /**
    56. * 参考AbstractErrorWebExceptionHandler
    57. */
    58. public void setMessageWriters(List> messageWriters) {
    59. Assert.notNull(messageWriters, "'messageWriters' must not be null");
    60. this.messageWriters = messageWriters;
    61. }
    62. @Override
    63. public Mono handle(ServerWebExchange exchange, Throwable ex) {
    64. // 按照异常类型进行处理
    65. HttpStatus httpStatus;
    66. String body;
    67. //todo 这里可以自己定义业务需要的异常
    68. if (ex instanceof ResponseStatusException) {
    69. ResponseStatusException responseStatusException = (ResponseStatusException) ex;
    70. httpStatus = responseStatusException.getStatus();
    71. body = responseStatusException.getMessage();
    72. } else {
    73. httpStatus = HttpStatus.INTERNAL_SERVER_ERROR;
    74. body = httpStatus.name();
    75. }
    76. ServerHttpRequest request = exchange.getRequest();
    77. log.error("[全局异常处理] 异常请求路径:{}, 记录异常信息:{}", request.getPath(), ex.getMessage());
    78. ex.printStackTrace();
    79. // 参考AbstractErrorWebExceptionHandler
    80. if (exchange.getResponse().isCommitted()) {
    81. return Mono.error(ex);
    82. }
    83. exceptionHandlerResult.set(ApiResult.error(httpStatus, body));
    84. ServerRequest newRequest = ServerRequest.create(exchange, this.messageReaders);
    85. return RouterFunctions.route(RequestPredicates.all(), this::renderErrorResponse).route(newRequest)
    86. .switchIfEmpty(Mono.error(ex))
    87. .flatMap((handler) -> handler.handle(newRequest))
    88. .flatMap((response) -> write(exchange, response));
    89. }
    90. /**
    91. * 参考DefaultErrorWebExceptionHandler
    92. * 在这里定义返回的是Json还是Html
    93. */
    94. protected Mono renderErrorResponse(ServerRequest request) {
    95. ApiResult result = exceptionHandlerResult.get();
    96. return ServerResponse.status(result.getCode())
    97. .contentType(MediaType.APPLICATION_JSON)
    98. .body(BodyInserters.fromValue(result));
    99. }
    100. /**
    101. * 参考AbstractErrorWebExceptionHandler
    102. */
    103. private Monoextends Void> write(ServerWebExchange exchange,
    104. ServerResponse response) {
    105. exchange.getResponse().getHeaders()
    106. .setContentType(response.headers().getContentType());
    107. return response.writeTo(exchange, new ResponseContext());
    108. }
    109. /**
    110. * 参考AbstractErrorWebExceptionHandler
    111. */
    112. private class ResponseContext implements ServerResponse.Context {
    113. @Override
    114. public List> messageWriters() {
    115. return CustomWebExceptionHandler.this.messageWriters;
    116. }
    117. @Override
    118. public List viewResolvers() {
    119. return CustomWebExceptionHandler.this.viewResolvers;
    120. }
    121. }
    122. }

    3. 定义返回数据格式

    1. import org.springframework.http.HttpStatus;
    2. import java.io.Serializable;
    3. public class ApiResult implements Serializable {
    4. private static final long serialVersionUID = 1166356696537391753L;
    5. private Integer code;
    6. private String msg;
    7. private T data;
    8. public ApiResult() {
    9. }
    10. public ApiResult(Integer code, String msg, T data) {
    11. this.code = code;
    12. this.msg = msg;
    13. this.data = data;
    14. }
    15. public static ApiResult success() {
    16. return new ApiResult(HttpStatus.OK.value(), "success", null);
    17. }
    18. public static ApiResult success(String msg) {
    19. return new ApiResult(HttpStatus.OK.value(), msg, null);
    20. }
    21. public static ApiResult success(String msg, Object data) {
    22. return new ApiResult(HttpStatus.OK.value(), msg, data);
    23. }
    24. public static ApiResult error(HttpStatus status, String msg) {
    25. return new ApiResult(status.value(), msg, null);
    26. }
    27. public Integer getCode() {
    28. return code;
    29. }
    30. public void setCode(Integer code) {
    31. this.code = code;
    32. }
    33. public String getMsg() {
    34. return msg;
    35. }
    36. public void setMsg(String msg) {
    37. this.msg = msg;
    38. }
    39. public T getData() {
    40. return data;
    41. }
    42. public void setData(T data) {
    43. this.data = data;
    44. }
    45. @Override
    46. public String toString() {
    47. return "Result{" +
    48. "code=" + code +
    49. ", msg='" + msg + '\'' +
    50. ", data=" + data +
    51. '}';
    52. }
    53. }

  • 相关阅读:
    2022-12-01 mysql列存储引擎-将exists子查询转换为between操作-分析
    [管理与领导-122]:IT人看清职场中的隐性规则 - 18- 一半佛一半魔,一半君子一半小人,阴阳互转,生生不息,儒、释、道、法,一个不能少
    nodejs中的错误类型及捕获处理
    【前端客栈】使用CSS实现畅销书排行榜页面
    5、MySQL——修改表结构、DQL(查询操作)、条件查询
    Linux查询mac物理地址
    场景图形管理-多视图与相机(3)
    教授先生带你学习并查集
    餐厅订位短信解决方案
    [附源码]java毕业设计书店网站论文
  • 原文地址:https://blog.csdn.net/RHHcainiao/article/details/133805197