Spring Cloud Gateway Hystrix fallback獲取異常信息的處理

Gateway Hystrix fallback獲取異常信息

gateway fallback後,需要知道請求的是哪個接口以及具體的異常信息,根據不同的請求以及異常進行不同的處理。一開始根據網上一篇博客上的做法:

pom.xml:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>

application.yml:

spring:
  cloud:
    gateway:
      discovery:
        locator:
          enabled: false
          lowerCaseServiceId: true
      routes:
        - id: auth-server
          uri: lb://MS-OAUTH2-SERVER
          predicates:
            - Path=/**
      default-filters:
        - name: Hystrix
          args:
            name: fallbackcmd
            fallbackUri: forward:/fallback

然後fallback就是這樣:

@RestController
@Slf4j
public class FallbackController {

    @RequestMapping(value = "/fallback")
    @ResponseStatus
    public Mono<Map<String, Object>> fallback(ServerWebExchange exchange, Throwable throwable) {
        Map<String, Object> result = new HashMap<>(3);
        ServerHttpRequest request = exchange.getRequest();
        log.error("接口調用失敗,URL={}", request.getPath().pathWithinApplication().value(), throwable);
        result.put("code", 60002);
        result.put("data", null);
        result.put("msg", "接口調用失敗!");
        return Mono.just(result);
    }
}

但是測試發現,這樣取出來的接口地址隻是“/fallback”本身,並且沒有異常信息:

在這裡插入圖片描述

後來我重新到HystrixGatewayFilterFactory類中去查看,發現瞭異常信息其實在exchange裡:

在這裡插入圖片描述

而請求的接口也通過debug找到瞭:

所以將代碼改成如下:

@RestController
@Slf4j
public class FallbackController {

    @RequestMapping(value = "/fallback")
    @ResponseStatus
    public Mono<Map<String, Object>> fallback(ServerWebExchange exchange) {
        Map<String, Object> result = new HashMap<>(3);
        result.put("code", 60002);
        result.put("data", null);
        Exception exception = exchange.getAttribute(ServerWebExchangeUtils.HYSTRIX_EXECUTION_EXCEPTION_ATTR);
        ServerWebExchange delegate = ((ServerWebExchangeDecorator) exchange).getDelegate();
        log.error("接口調用失敗,URL={}", delegate.getRequest().getURI(), exception);
        if (exception instanceof HystrixTimeoutException) {
            result.put("msg", "接口調用超時");
        } else if (exception != null && exception.getMessage() != null) {
            result.put("msg", "接口調用失敗: " + exception.getMessage());
        } else {
            result.put("msg", "接口調用失敗");
        }
        return Mono.just(result);
    }
}

正常取到請求路徑以及異常信息:

關於 hystrix 的異常 fallback method wasn’t found

消費者服務–service 的實現如下:

@Service
public class BookService {
    @Autowired
    public RestTemplate  restTemplate;
    @HystrixCommand(fallbackMethod = "addServiceFallback")
    public  Book   getBook( Integer  bookId ){
        return  restTemplate.getForObject("http://provider-service/boot/book?bookId={bookId}",Book.class , bookId);
    }
    public  String  addServiceFallback(){
        System.out.println("error addServiceFallback.... ");
        return  "error" ;
    }
}

就會出現如下所述的異常

Whitelabel Error Page
This application has no explicit mapping for /error, so you are seeing this as a fallback.

Fri May 25 14:27:51 CST 2018
There was an unexpected error (type=Internal Server Error, status=500).
fallback method wasn’t found: addServiceFallback([class java.lang.Integer])

這是因為指定的 備用方法 addServiceFallback 和 原方法getBook 的參數個數,參數類型 不同造成的;

修改addServiceFallback 方法:

public  String addServiceFallback(Integer  bookId){
    System.out.println("error addServiceFallback.... ");
    return  "error" ;
}

繼續運行,就會出現如下所述的異常

Whitelabel Error Page
This application has no explicit mapping for /error, so you are seeing this as a fallback.

Fri May 25 14:32:24 CST 2018
There was an unexpected error (type=Internal Server Error, status=500).
Incompatible return types. Command method: public com.bmcc.springboot.model.Book com.bmcc.springboot.service.BookService.getBook(java.lang.Integer); Fallback method: public java.lang.String com.bmcc.springboot.service.BookService.addServiceFallback(java.lang.Integer); Hint: Fallback method ‘public java.lang.String com.bmcc.springboot.service.BookService.addServiceFallback(java.lang.Integer)’ must return: class com.bmcc.springboot.model.Book or its subclass

這是因為指定的 備用方法 addServiceFallback 和 原方法getBook 雖然 參數個數,參數類型 相同 ,但是 方法的返回值類型不同造成的;

修改addServiceFallback 方法:

public  Book  addServiceFallback(Integer  bookId){
    System.out.println("error addServiceFallback.... ");
    return  new Book() ;
}

繼續運行,這樣就可以看到當一個服務提供者異常關閉時, 消費者(消費者采用輪詢的方式消費服務)再繼續訪問服務時,不會拋出異常頁面,而是如下:

{"bookId":0,"bookName":null,"price":null,"publisher":null}

以上為個人經驗,希望能給大傢一個參考,也希望大傢多多支持WalkonNet。

推薦閱讀: