在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 里面的信息, 拿到相应的异常.

CircuitBreaker断路器Fallback如何获取异常的更多相关文章

  1. Python中获取异常(Exception)信息

    异常信息的获取对于程序的调试非常重要,可以有助于快速定位有错误程序语句的位置.下面介绍几种python中获取异常信息的方法,这里获取异常(Exception)信息采用try...except...程序 ...

  2. ASP.NET Web API 异常处理 HttpResponseException 以及Angularjs获取异常信息并提示

    一.HttpResponseException 如果一个Web API控制器抛出一个未捕捉异常,默认地,大多数异常都会被转化成一个带有状态码“500 – 内部服务器错误”的HTTP响应.HttpRes ...

  3. Java异常---获取异常的堆栈信息

    Java 实例 - 获取异常的堆栈信息  Java 实例 以下实例演示了使用异常类的 printStack() 方法来获取堆栈信息: Main.java 文件 public class Main{ p ...

  4. 获取异常信息e.printStackTrace()的内容

    获取异常信息e.printStackTrace()的内容 最近做项目的时候需要记录操作的日志,但是记录异常信息的是发现使用e.getMessage()根本无法满足需要,并且e.getMessage() ...

  5. oracle存储过程获取异常信息码和异常信息

    oracle存储过程,可以通过sqlcode 获取异常编码.通过sqlerrm获取异常信息. 例子: create or replace procedure write2blob(p_id in nu ...

  6. Python中获取异常(try Exception)信息

    异常信息的获取对于程序的调试非常重要,可以有助于快速定位有错误程序语句的位置. 这里获取异常(Exception)信息采用try...except...程序结构.如下所示: try: ... exce ...

  7. SQL server 获取异常

    一.try...... catch 获取异常信息 /*======================================== 相关错误消 息如下: ERROR_NUMBER() 返回错误号. ...

  8. 获取异常信息里再出异常就找不到日志了,我TM人傻了

    本系列是 我TM人傻了 系列第三期[捂脸],往期精彩回顾: 升级到Spring 5.3.x之后,GC次数急剧增加,我TM人傻了 这个大表走索引字段查询的 SQL 怎么就成全扫描了,我TM人傻了 最近组 ...

  9. 权限获取异常(不能用ModuleId,得换个名字)目前还没搞清楚为啥

    CenterController: /// <summary> /// 访问模块,写入系统菜单Id /// </summary> /// <param name=&quo ...

随机推荐

  1. 12、windows定时备份数据库

    12.1.删除指定目录中的内容: del /Q E:\DATABAK\* copy 1.txt bak\a.txt 12.2.可用的备份计划: 1.脚本: BakScripts @echo off R ...

  2. springCloud学习05之api网关服务zuul过滤器filter

    前面学习了zuul的反向代理.负载均衡.fallback回退.这张学习写过滤器filter,做java web开发的对filter都不陌生,那就是客户端(如浏览器)发起请求的时候,都先经过过滤器fil ...

  3. PHP 跨域问题 (转)

    通过设置Access-Control-Allow-Origin来实现跨域. 例如:客户端的域名是client.runoob.com,而请求的域名是server.runoob.com. 如果直接使用aj ...

  4. Leetcode No.27 Remove Element(c++实现)

    1. 题目 1.1 英文题目 Given an integer array nums and an integer val, remove all occurrences of val in nums ...

  5. 腾讯云短信详细教程(C#,WinForm)

    1.申请一个微信公众号(申请公众号是准备工作的第一步,必须先完成)(那为什么要用公众号呢?是因为这个条件对于学生党来说比较简单实现,不需要本人有上市的APP或是网站等) 2.百度搜索"腾讯云 ...

  6. Jmeter使用笔记001

    Apache JMeter是一款纯java编写负载功能测试和性能测试开源工具软件. jmeter也可以用来做接口自动化 一.jmeter基础 1.1 jmeter的执行顺序 1,执行配置元件2,前置处 ...

  7. IDA 修改后保存

    关键点找到了.把 jz short loc_10004753 改成jnz short loc_10004753即可. IDA->edit->Patch program->Assemb ...

  8. vue3如何编写挂载DOM的插件

    vue3 跟 vue2 相比,多了一个 app 的概念,vue3 项目的创建也变成了 // main.jsimport { createApp } from 'vue' import App from ...

  9. spring boot(二)整合mybatis plus+ 分页插件 + 代码生成

    先创建spring boot项目,不知道怎么创建项目的 可以看我上一篇文章 用到的环境 JDK8 .maven.lombok.mysql 5.7 swagger 是为了方便接口测试 一.Spring ...

  10. 导出数据在exlcel上

    1.前台写一个按钮跳到控制层 <a href="account.do?flag=out" >导出表格</a> 2.控制层导出数据方法 @RequestMap ...