• Spring Cloud Gateway配置自定义异常返回


    0. 前言

      最近搞微服务的全家桶,用到的Spring Cloud Gateway 这个组件。需要对这个网关抛出的异常进行自定义。网关的异常处理跟单体SpringBoot的全局异常处理还有点不一样。

      单体全局异常处理,是采用@RestControllerAdvice 这个注解来实现的。微服务Gateway是采用另外的方式来实现的。

    1. 单体自定义异常返回

      CustomException.java

     1 package com.wunaozai.config.advice;
     2 
     3 /**
     4  * 自定义异常类(运行时异常)
     5  * @author wunaozai
     6  * @date 2018-06-27
     7  */
     8 public class CustomException extends RuntimeException {
     9 
    10     private static final long serialVersionUID = 6304501072268270030L;
    11     
    12     public CustomException(String msg) {
    13         this(500, msg);
    14     }
    15     public CustomException(int code, String msg) {
    16         this(code, msg, null);
    17     }
    18     public CustomException(String msg, Object data) {
    19         this(500, msg, data);
    20     }
    21     public CustomException(int code, String msg, Object data) {
    22         super(msg);
    23         this.code = code;
    24         this.msg = msg;
    25         this.data = data;
    26     }
    27     
    28 
    29     /**
    30      * 异常代码
    31      */
    32     private int code;
    33     /**
    34      * 异常信息
    35      */
    36     private String msg;
    37     /**
    38      * 异常调试信息
    39      */
    40     private Object data;
    41     
    42     /**
    43      * 异常代码
    44      * @return code 
    45      */
    46     public int getCode() {
    47         return code;
    48     }
    49     /**
    50      * 异常代码
    51      * @param code 异常代码
    52      */
    53     public void setCode(int code) {
    54         this.code = code;
    55     }
    56     /**
    57      * 异常信息
    58      * @return msg 
    59      */
    60     public String getMsg() {
    61         return msg;
    62     }
    63     /**
    64      * 异常信息
    65      * @param msg 异常信息
    66      */
    67     public void setMsg(String msg) {
    68         this.msg = msg;
    69     }
    70     /**
    71      * 异常调试信息
    72      * @return data 
    73      */
    74     public Object getData() {
    75         return data;
    76     }
    77     /**
    78      * 异常调试信息
    79      * @param data 异常调试信息
    80      */
    81     public void setData(Object data) {
    82         this.data = data;
    83     }
    84 }

      CustomControllerAdvice.java

     1 package com.wunaozai.config.advice;
     2 
     3 import java.util.HashMap;
     4 import java.util.Map;
     5 
     6 import org.springframework.ui.Model;
     7 import org.springframework.web.bind.WebDataBinder;
     8 import org.springframework.web.bind.annotation.ExceptionHandler;
     9 import org.springframework.web.bind.annotation.InitBinder;
    10 import org.springframework.web.bind.annotation.ModelAttribute;
    11 import org.springframework.web.bind.annotation.RestControllerAdvice;
    12 
    13 import com.baomidou.mybatisplus.extension.api.R;
    14 
    15 /**
    16  * 控制器Controller异常处理
    17  * @author wunaozai
    18  * @Date 2020-03-05
    19  */
    20 @RestControllerAdvice
    21 public class CustomControllerAdvice {
    22     
    23     /**
    24      * 应用到所有@RequestMapper 注解方法,在其执行之前初始化数据绑定器
    25      * @param binder
    26      */
    27     @InitBinder
    28     public void initBinder(WebDataBinder binder) {
    29         
    30     }
    31     
    32     /**
    33      * 把值绑定到Model中,使全局@RequestMapper可以获取到该值
    34      * @param model
    35      */
    36     @ModelAttribute
    37     public void addAttributes(Model model) {
    38         model.addAttribute("Server", "Wunaozai");
    39     }
    40     
    41     @ExceptionHandler(value= {Exception.class, CustomException.class})
    42     public R<String> errorHandler(Exception ex){
    43         Map<String, Object> map = new HashMap<>();
    44         map.put("code", 500);
    45         map.put("msg", ex.getMessage());
    46         System.out.println("异常Handler.");
    47         ex.printStackTrace();
    48         //System.out.println(resuserService.count());
    49         return R.failed(ex.getMessage());
    50     }
    51 }

    2. 微服务Gateway自定义异常返回

      JsonExceptionHandler.java

     1 package com.wunaozai.config.exception;
     2 
     3 import java.util.HashMap;
     4 import java.util.Map;
     5 
     6 import org.springframework.boot.autoconfigure.web.ErrorProperties;
     7 import org.springframework.boot.autoconfigure.web.ResourceProperties;
     8 import org.springframework.boot.autoconfigure.web.reactive.error.DefaultErrorWebExceptionHandler;
     9 import org.springframework.boot.web.reactive.error.ErrorAttributes;
    10 import org.springframework.cloud.gateway.support.NotFoundException;
    11 import org.springframework.context.ApplicationContext;
    12 import org.springframework.http.HttpStatus;
    13 import org.springframework.web.reactive.function.server.RequestPredicates;
    14 import org.springframework.web.reactive.function.server.RouterFunction;
    15 import org.springframework.web.reactive.function.server.RouterFunctions;
    16 import org.springframework.web.reactive.function.server.ServerRequest;
    17 import org.springframework.web.reactive.function.server.ServerResponse;
    18 
    19 import lombok.extern.slf4j.Slf4j;
    20 
    21 /**
    22  * 序列化
    23  * @author wunaozai
    24  * @Date 2020-06-04
    25  */
    26 @Slf4j
    27 public class JsonExceptionHandler extends DefaultErrorWebExceptionHandler {
    28 
    29     public JsonExceptionHandler(ErrorAttributes errorAttributes, ResourceProperties resourceProperties,
    30             ErrorProperties errorProperties, ApplicationContext applicationContext) {
    31         super(errorAttributes, resourceProperties, errorProperties, applicationContext);
    32     }
    33 
    34     @Override
    35     protected Map<String, Object> getErrorAttributes(ServerRequest request, boolean includeStackTrace) {
    36         int code = HttpStatus.INTERNAL_SERVER_ERROR.value();
    37         Throwable error = super.getError(request);
    38 //        if(error instanceof NotFoundException) {
    39 //            code = HttpStatus.NOT_FOUND.value();
    40 //        }
    41         return response(code, this.buildMessage(request, error));
    42     }
    43 
    44     /**
    45      * 指定响应处理方法为JSON处理的方法
    46      * @param errorAttributes
    47      */
    48     @Override
    49     protected RouterFunction<ServerResponse> getRoutingFunction(ErrorAttributes errorAttributes) {
    50         return RouterFunctions.route(RequestPredicates.all(), this::renderErrorResponse);
    51     }
    52 
    53 
    54     /**
    55      * 根据code获取对应的HttpStatus
    56      * @param errorAttributes
    57      */
    58     @Override
    59     protected int getHttpStatus(Map<String, Object> errorAttributes) {
    60         int statusCode = (int) errorAttributes.get("code");
    61         return statusCode;
    62     }
    63 
    64     /**
    65      * 构建异常信息
    66      * @param request
    67      * @param ex
    68      * @return
    69      */
    70     private String buildMessage(ServerRequest request, Throwable ex) {
    71         StringBuilder message = new StringBuilder("Failed to handle request [");
    72         message.append(request.methodName());
    73         message.append(" ");
    74         message.append(request.uri());
    75         message.append("]");
    76         if (ex != null) {
    77             message.append(": ");
    78             message.append(ex.getMessage());
    79         }
    80         return message.toString();
    81     }
    82 
    83     /**
    84      * 构建返回的JSON数据格式
    85      * @param status        状态码
    86      * @param errorMessage  异常信息
    87      * @return
    88      */
    89     public static Map<String, Object> response(int status, String errorMessage) {
    90         Map<String, Object> map = new HashMap<>();
    91         map.put("code", status);
    92         map.put("message", errorMessage);
    93         map.put("data", null);
    94         log.error(map.toString());
    95         return map;
    96     }
    97 }

      ExceptionHandlerConfiguration.java

     1 package com.wunaozai.config.exception;
     2 
     3 import java.util.Collections;
     4 import java.util.List;
     5 
     6 import org.springframework.beans.factory.ObjectProvider;
     7 import org.springframework.boot.autoconfigure.web.ResourceProperties;
     8 import org.springframework.boot.autoconfigure.web.ServerProperties;
     9 import org.springframework.boot.context.properties.EnableConfigurationProperties;
    10 import org.springframework.boot.web.reactive.error.ErrorAttributes;
    11 import org.springframework.boot.web.reactive.error.ErrorWebExceptionHandler;
    12 import org.springframework.context.ApplicationContext;
    13 import org.springframework.context.annotation.Bean;
    14 import org.springframework.context.annotation.Configuration;
    15 import org.springframework.core.Ordered;
    16 import org.springframework.core.annotation.Order;
    17 import org.springframework.http.codec.ServerCodecConfigurer;
    18 import org.springframework.web.reactive.result.view.ViewResolver;
    19 
    20 /**
    21  * 自定义异常处理<br>
    22  * https://www.cnblogs.com/viaiu/p/10403557.html
    23  * @author wunaozai
    24  * @Date 2020-06-04
    25  */
    26 @Configuration
    27 @EnableConfigurationProperties({ ServerProperties.class, ResourceProperties.class })
    28 public class ExceptionHandlerConfiguration {
    29 
    30     private final ServerProperties serverProperties;
    31 
    32     private final ApplicationContext applicationContext;
    33 
    34     private final ResourceProperties resourceProperties;
    35 
    36     private final List<ViewResolver> viewResolvers;
    37 
    38     private final ServerCodecConfigurer serverCodecConfigurer;
    39 
    40     public ExceptionHandlerConfiguration(ServerProperties serverProperties, ResourceProperties resourceProperties,
    41             ObjectProvider<List<ViewResolver>> viewResolversProvider, ServerCodecConfigurer serverCodecConfigurer,
    42             ApplicationContext applicationContext) {
    43         this.serverProperties = serverProperties;
    44         this.applicationContext = applicationContext;
    45         this.resourceProperties = resourceProperties;
    46         this.viewResolvers = viewResolversProvider.getIfAvailable(Collections::emptyList);
    47         this.serverCodecConfigurer = serverCodecConfigurer;
    48     }
    49 
    50     @Bean
    51     @Order(Ordered.HIGHEST_PRECEDENCE)
    52     public ErrorWebExceptionHandler errorWebExceptionHandler(ErrorAttributes errorAttributes) {
    53         JsonExceptionHandler exceptionHandler = new JsonExceptionHandler(errorAttributes, this.resourceProperties,
    54                 this.serverProperties.getError(), this.applicationContext);
    55         exceptionHandler.setViewResolvers(this.viewResolvers);
    56         exceptionHandler.setMessageWriters(this.serverCodecConfigurer.getWriters());
    57         exceptionHandler.setMessageReaders(this.serverCodecConfigurer.getReaders());
    58         return exceptionHandler;
    59     }
    60 }

       处理前异常返回

      自定义后异常返回

     

    参考资料: https://www.cnblogs.com/viaiu/p/10403557.html

    本文地址: https://www.cnblogs.com/wunaozai/p/13043979.html

     

  • 相关阅读:
    《微服务架构设计》——Eventuate Tram框架订阅/消费模式源码解析
    Spring Cloud LoadBalancer原理讲解及自定义负载均衡器
    聊一下 TS 中的交叉类型
    如何理解 TS 类型编程中的 extends 和 infer
    TS 中 never 类型的妙用
    28岁大龄青年相亲记——2021年总结与思考
    Kafka从入门到放弃(三)—— 详说消费者
    Kafka从入门到放弃(二) —— 详说生产者
    Kafka从入门到放弃(一) —— 初识Kafka
    短时间复习通过2021上半年软考软件设计师(附资料)
  • 原文地址:https://www.cnblogs.com/wunaozai/p/13043979.html
Copyright © 2020-2023  润新知