Spring Cloud实战小贴士:Zuul统一异常处理(三)【Dalston版】

本篇作为《Spring Cloud微服务实战》一书关于Spring Cloud Zuul网关在Dalston版本对异常处理的补充。没有看过本书的读书也不要紧,可以先阅读我之前的两篇博文:《Spring Cloud实战小贴士:Zuul统一异常处理(一)》和《Spring Cloud实战小贴士:Zuul统一异常处理(二)》,这两篇文章都详细介绍和分析了Spring Cloud Zuul在过滤器设计中对异常处理的不足。同时,在这两篇文章中,也针对不足之处做了相应的解决方案。不过,这些方案都是基于Brixton版本所做的,在最新的Dalston版本中,Spring Cloud Zuul做了一些优化,所以我们不再需要做这些扩展就已经能够正确的处理异常信息了。那么,在Dalston版中,Spring Cloud Zuul中做了怎么样的修改以达到之前我们自己扩展的效果呢?

过滤器类型的变更

读者是否还记得我们之前分析了Spring Cloud Zuul自带的核心过滤器有哪些呢?我们先根据下图回忆一下:

这次主要将 SendErrorFilter过滤器的类型从 POST改为了 ERROR,所以核心过滤器变成了如下图的结构:

处理逻辑的变化

既然过滤器类型发生了变化,那么请求的处理生命周期就会有所变化。在变化之前,各阶段过滤器的流转如下图所示:

针对异常情况,在图中我们标出了不同的颜色。从pre和route阶段抛出的异常将会进入error阶段,再进入到post阶段进行返回。由于SendErrorFilter需要判断请求上下文中是否包含 error.status_code属性:有的话就用SendErrorFilter处理错误结果;没有的话就用SendResponseFilter返回正常结果,但是 error.status_code属性默认是在各个阶段过滤器中自己put进去的,这就导致,各个阶段过滤器抛出异常之后,是没有办法返回错误结果的。因此,我们扩展了一个ErrorFilter来捕获异常,然后手工的设置 error.status_code属性,让SendErrorFilter能正常运作。

通过上面你的改造,从pre和route阶段的异常都能处理了,但是post阶段抛出异常后,是不会再进入post阶段的,这使得ErrorFilter设置了设置 error.status_code属性之后,也没有过滤器去组织返回结果,所以我们通过继承SendErrorFilter在error阶段增加了一个返回错误信息的过滤器。

而这次在Dalston版本中,做了很巧妙的变动:就是上文所述的对SendErrorFilter过滤器类型的变更,这一变动使得所有阶段的异常都会被SendErrorFilter处理,直接解决的上面的第二个问题。当然只是做个变动还是不够的,为了区分SendErrorFilter和SendResponseFitler分别处理出现异常和未出现异常的情况,修改原来根据 error.status_code属性判断的逻辑,而是改为根据请求上下文中是否包含Throwable来作为基本依据,而这个对象是在过滤器出现异常之后,Zuul往请求上下文中置入的,所以可以更为准确的判断当前请求处理是否出现了异常,而不再需要我们之前扩展的ErrorFilter了。

public class SendErrorFilter extends ZuulFilter {        
@Override    

public boolean shouldFilter() {        
RequestContext ctx = RequestContext.getCurrentContext();       
 return ctx.containsKey("error.status_code")               
  && !ctx.getBoolean(SEND_ERROR_FILTER_RAN, false);    }    
  ...
  
  }
  public class SendResponseFilter extends ZuulFilter {    
  @Override    
  public boolean shouldFilter() {      
    RequestContext context = RequestContext.getCurrentContext();        
    return context.getThrowable() == null && (!context.getZuulResponseHeaders().isEmpty()|| 
    context.getResponseDataStream() != null
|| context.getResponseBody() != null);   
 }    
 ...}

所以,最后修改之后,整个处理逻辑变为如下图所示的流程:

原文发布于微信公众号 - 程序猿DD(didispace)

原文发表时间:2017-08-02

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏世界第一语言是java

网站调用支付宝进行支付-Java后台调用支付宝支付

6893
来自专栏阿杜的世界

实践基于Redis的分布式锁应用场景实现方式基于Redis的实践参考资料

本文来自社区这周的讨论话题—— 技术专题讨论第四期:漫谈分布式锁,也总结了我对分布式锁的认知和使用经验。

2233
来自专栏程序猿DD

Spring Batch入门篇

Spring Batch,一个很多人还觉得陌生的框架,它是Spring Cloud Task的基础,主要用来实现批量任务的处理。该框架在国内的使用非常少,所以一...

2765
来自专栏ChaMd5安全团队

Real World CTF国际大赛 部分WP

题目描述里写平台很安全,请不要攻击。 所以尝试抓包,往Cookie的uid进行sqli

1491
来自专栏Jerry的SAP技术分享

Hybris Enterprise Commerce Platform 服务层的设计与实现

Hybris Enterprise Commerce Platform这个系列之前已经由我的同事,SAP成都研究院Hybris开发团队的同事张健(Zhang J...

1112
来自专栏LinkedBear的个人空间

浅析RPC与WebService

虽然现在非常火的RPC技术以SpringCloud和Dubbo(x)为主流,但是如果做接口调用,还是逃不了要用一些较传统的技术。前几天在做接口调用时恰巧用到了W...

3171
来自专栏小李刀刀的专栏

[译]Laravel 5.0 之命令及处理程序

本文译自 Matt Stauffer 的系列文章. ---- 本文中涉及的新功能都是关于 Commands 的,这些特性在 Laravel 旧版本中已经有了,但...

3596
来自专栏Android群英传

NDK Maping 发布啦

1102
来自专栏高性能服务器开发

redis网络通信模块源码分析(下)

这里注册可写事件AE_WRITABLE的回调函数是sendReplyToClient。也就是说,当下一次某个触发可写事件时,调用的就是sendReplyToCl...

3444
来自专栏程序猿DD

Spring Cloud实战小贴士:Zuul处理Cookie和重定向

由于我们在之前所有的入门教程中,对于HTTP请求都采用了简单的接口实现。而实际使用过程中,我们的HTTP请求要复杂的多,比如当我们将Spring Cloud Z...

6856

扫码关注云+社区

领取腾讯云代金券