CircuitBreaker斷路器Fallback如何獲取異常
阿新 • • 發佈:2021-08-16
在Spring Cloud 2020新版裡, 可以使用新版的 CircuitBreaker 斷路器, 可以配置Fallback, 可以是內部的, 也可以是外部的Fallback.
內部 Fallback
這裡搭建一個內部fallback, 配置如下:
server: port: 8900 spring: application: name: ms-gateway main: allow-bean-definition-overriding: true cloud: zookeeper: connect-string: ${ZK_HOSTS:127.0.0.1:2181} discovery: enabled: true preferIpAddress: true loadbalancer: ribbon: enabled: false gateway: discovery: locator: lowerCaseServiceId: true enabled: true routes: - id: default uri: lb://ms-fundmain-service predicates: - Path=/fundmain/** filters: - StripPrefix=1 - name: CircuitBreaker args: name: fetchIngredients fallbackUri: forward:/defaultfallback - name: Retry args: retries: 2 series: SERVER_ERROR
fallback攔截了服務端異常, defaultfallback的實現如下:
@RestController public class DefaultFallback { private static final Logger logger = LoggerFactory.getLogger(GatewayErrorAttributes.class); @RequestMapping("/defaultfallback") @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) public Map<String, Object> defaultfallback() { Map<String, Object> map = new HashMap<>(); map.put("code", 5001); map.put("msg", "服務異常"); return map; } }
這樣就可以實現一個最簡單的fallback, 如果要獲取服務的實際錯誤資訊, 則改造如下:
@RestController public class DefaultFallback { private static final Logger logger = LoggerFactory.getLogger(GatewayErrorAttributes.class); @RequestMapping(value = "/defaultfallback") @ResponseStatus public Mono<Map<String, Object>> fallback(ServerWebExchange exchange) { Map<String, Object> result = new HashMap<>(4); result.put("code", 5001); Exception exception = exchange.getAttribute(ServerWebExchangeUtils.CIRCUITBREAKER_EXECUTION_EXCEPTION_ATTR); ServerWebExchange delegate = ((ServerWebExchangeDecorator) exchange).getDelegate(); logger.error("服務呼叫失敗,URL={}", delegate.getRequest().getURI(), exception); result.put("uri", delegate.getRequest().getURI()); if (exception instanceof TimeoutException) { result.put("msg", "服務超時"); } else if (exception != null && exception.getMessage() != null) { result.put("msg", "服務錯誤: " + exception.getMessage()); } else { result.put("msg", "服務錯誤"); } return Mono.just(result); } }
這次注入了一個 ServerWebExchange, 然後獲取儲存在 CIRCUITBREAKER_EXECUTION_EXCEPTION_ATTR 裡面的例項, 拿到相應的異常資訊.
外部Fallback
請參考 https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/, 使用 FallbackHeaders 即可.
spring:
application:
name: ms-gateway
main:
allow-bean-definition-overriding: true
redis:
host: 127.0.0.1
port: 6379
database: 0
cloud:
zookeeper:
connect-string: ${ZK_HOSTS:127.0.0.1:2181}
discovery:
enabled: true
preferIpAddress: true
loadbalancer:
ribbon:
enabled: false
gateway:
discovery:
locator:
lowerCaseServiceId: true
enabled: true
routes:
- id: testoutsidefallback
uri: lb://ms-fundmain-service
predicates:
- Path=/fundmain2/**
filters:
- StripPrefix=1
- name: CircuitBreaker
args:
name: fetchIngredients2
fallbackUri: forward:/externalfallback
- id: ingredients-fallback
uri: lb://ms-fundmain-service
predicates:
- Path=/externalfallback
filters:
- name: FallbackHeaders
args:
executionExceptionTypeHeaderName: Exception-Type
executionExceptionMessageHeaderName: Exception-Message
支援四個欄位:
- executionExceptionTypeHeaderName ("Execution-Exception-Type")
- executionExceptionMessageHeaderName ("Execution-Exception-Message")
- rootCauseExceptionTypeHeaderName ("Root-Cause-Exception-Type")
- rootCauseExceptionMessageHeaderName ("Root-Cause-Exception-Message")
實現示例 Fallback如下: (注意, 此Controller不能放在閘道器專案裡, 否則就要用內部Fallback才行)
@RestController
public class ExternalFallback {
private static final Logger logger = LoggerFactory.getLogger(ExternalFallback.class);
private static final String EXECUTION_EXCEPTION_TYPE = "Exception-Type";
private static final String EXECUTION_EXCEPTION_MESSAGE = "Exception-Message";
@RequestMapping("/externalfallback")
@ResponseStatus
public Map<String, Object> externalfallback(HttpServletRequest request) {
Map<String, Object> map = new HashMap<>();
map.put("code", 5002);
map.put("msg", "服務異常");
map.put(EXECUTION_EXCEPTION_TYPE, request.getHeader(EXECUTION_EXCEPTION_TYPE));
map.put(EXECUTION_EXCEPTION_MESSAGE, request.getHeader(EXECUTION_EXCEPTION_MESSAGE));
return map;
}
}
這次注入了一個 HttpServletRequest, 然後獲取儲存在 Header 裡面的資訊, 拿到相應的異常.
本文來自部落格園,作者:飛雲~風之谷,轉載請註明原文連結:https://www.cnblogs.com/cnscud/p/15149414.html