过滤器

Zuul包括两部分内容:请求的路由和过滤。而实际上请求的路由也是通过过滤器实现的,例如理由映射主要通过pre类型的过滤器完成,它将请求路径与配置的路由规则进行匹配,找到需要转发的目标地址;请求转发的部分则是由route类型的过滤器来完成的,对pre类型过滤器获得的路由地址进行转发。所以过滤器时Zuul实现API网关功能最为核心的部件,每一个进入Zuul的Http请求都会经过一系列的过滤器处理链得到请求响应并返回给客户端。

ZuulFilter接口四特征

过滤类型、执行顺序、执行条件、具体操作

  • 过滤类型 filterType

    pre:在请求被路由之前调用

    routing: 在请求路由时被调用

    post: 在routing和error过滤器之后被调用

    error: 处理请求时发生错误时被调用
  • 执行顺序 filterOrder

    通过int值来定义过滤器的执行顺序,数值越小,优先级越高
  • 执行条件 shouldFilter

    返回一个boolean值来判断该过滤器是否要执行,可通过此方法来指定过滤器的有效范围
  • 具体操作 run

    过滤器的具体逻辑。通过过滤逻辑来确定是否要拦截当前的请求,否则对请求进行一些加工

核心过滤器

过滤器类型 顺序 过滤器 功能
pre -3 ServletDetectionFilter 标记处理Servlet的类型
pre -2 Servlet30WrapperFilter 包装HttpServletRequest请求
pre -1 FormBodyWrapperFilter 包装请求体
pre 1 DebugFilter 标记调试标志
pre 5 PreDecorationFilter 处理请求上下文供后续使用
route 10 RibbonRoutingFilter serviceId请求转发
route 100 SimpleHostRoutingFilter url请求转发
route 500 SendForwordFilter forward请求转发
post 0 SendErrorFilter 处理有错误的请求响应
post 1000 SendResponseFilter 处理正常处理的请求响应

异常处理

已知异常处理

对于可预知异常处理,可以使用SendErrorFilter处理

SendErrorFilter过滤器对异常处理的触发条件是,异常信息必须包含error.status_code错误信息,所以在进行异常处理的时候需要在异常信息中添加error.status_code信息用来出发SendErrorFilter。

未知异常处理

对于不可预知的异常需要使用全局异常处理,即使用ErrorFilter处理

在请求生命周期的pre、route、post三个阶段中有异常抛出的时候都会进入error阶段的处理,所以可以创建一个error类型的过滤器来捕获这些异常信息,并根据这些异常信息在请求上下文中注入需要返回给客户端的错误描述。常见用法是,在try-catch中注入error信息,让SendErrorFilter捕获处理返回给客户端,eg:

public class ErrorFilter extends ZuulFilter
{
private static final Logger log = LoggerFactory.getLogger(ErrorFilter.class);
@Override
public String filterType()
{
return "error";
} @Override
public int filterOrder()
{
return 10;
} @Override
public boolean shouldFilter()
{
return true;
} @Override
public Object run()
{
RequestContext ctx = RequestContext.getCurrentContext();
Throwable throwable = ctx.getThrowable();
log.error("this is a ErrorFilter:{}.", throwable.getCause().getMessage());
ctx.set("error.status_code", HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
ctx.set("error.exception", throwable.getCause());
return null;
}
}

第一种是在开发过程中对异常的处理,第二种是对第一种的补充,防止意外异常发生

三种过滤器类型调用过程

try{
preRoute();
}catch(ZuulException e){
error(e);
postRoute();
return;
}
try{
route();
}catch(ZuulException e){
error(e);
postRoute();
return;
}
try{
postRoute();
}catch(ZuulException){
error(e);
return;
}

在pre、route过滤器调用过程中,抛出异常都要经过error过滤器处理,然后再通过post返回客户端。但是,如果在post中出现了异常,由error过滤器处理后并不会再调用post阶段的请求,这些error.*参数就不会被SendErrorFilter消费输出,会造成异常泄露

处理方法

在error过滤器之后在加一层SendErrorFilter,用来执行post过滤器中抛出的异常

public class ErrorExtFilter extends SendErrorFilter
{
@Override
public String filterType()
{
return "error";
} @Override
public int filterOrder()
{
return 30;
} @Override
public boolean shouldFilter()
{
//TODO
return true;
}
}

那么怎样判断过滤器来自于哪个阶段呢,需要重写FilterProcessor核心过滤器类,在执行filter具体逻辑的方法processZuulFilter方法中对处理的filter进行标记

public class MarkFilterProcessor extends FilterProcessor
{
@Override
public Object processZuulFilter(ZuulFilter filter) throws ZuulException
{
try
{
return super.processZuulFilter(filter);
}
catch (ZuulException e)
{
RequestContext ctx = RequestContext.getCurrentContext();
ctx.set("failed.filter", filter);
throw e;
}
}
}

在shouldFilter方法中进行判断是不是post阶段抛出的异常

@Override
public boolean shouldFilter()
{
RequestContext ctx = RequestContext.getCurrentContext();
ZuulFilter failedFilter = (ZuulFilter) ctx.get("failed.filter");
if(failedFilter != null && failedFilter.filterType().equals("post"))
{
return true;
}
return false;
}

最后在主类中调用FilterProcessor.setProcessor(new MarkFilterProcessor());启动自定义的核心处理器

自定义异常信息

默认使用DefaultErrorAttributes作为默认异常信息接口,如果有ErrorAttributes接口的实现类,则不适用默认的,而使用实现类

  • 自定义实现类,重写getErrorAttributes方法

    移除message中的exception属性
public class MessageErrorAttributes extends DefaultErrorAttributes
{
@Override
public Map<String, Object> getErrorAttributes(RequestAttributes requestAttributes, boolean includeStackTrace)
{
Map<String, Object> result = super.getErrorAttributes(requestAttributes, includeStackTrace);
result.remove("exception");
return result;
}
}
  • 加入主类
public DefaultErrorAttributes errorAttributes()
{
return new MessageErrorAttributes();
}

禁用过滤器(包括自定义+默认)

zuul.<filtername>.<filtertype>.disable=true

动态路由

使用spring cloud config分布式配置中心实现application.properties/application.yarm动态加载

动态过滤器

Spring cloud学习--Zuul02的更多相关文章

  1. spring cloud 学习(9) - turbine stream无法在eureka注册的解决办法

    turbine是啥就不多解释了,初次接触的可以移步spring cloud 学习(4) - hystrix 服务熔断处理 拉到最后看一下,turbine stream默认情况下启动成功后,eureka ...

  2. Spring Cloud学习(一):Eureka服务注册与发现

    1.Eureka是什么 Eureka是Netflix开发的服务发现框架,本身是一个基于REST的服务,主要用于定位运行在AWS域中的中间层服务,以达到负载均衡和中间层服务故障转移的目的. Eureka ...

  3. spring cloud 学习资料

    spring cloud 学习资料 网址 拜托!面试请不要再问我Spring Cloud底层原理 https://mp.weixin.qq.com/s/ZH-3JK90mhnJPfdsYH2yDA

  4. Spring Boot和Spring Cloud学习资源推荐

    Spring Boot和Spring Cloud学习资源推荐   比较好的学习资源,分享一下. 1.Spring Boot官方文档:http://projects.spring.io/spring-b ...

  5. Spring Cloud 学习 之 Spring Cloud Eureka(源码分析)

    Spring Cloud 学习 之 Spring Cloud Eureka(源码分析) Spring Boot版本:2.1.4.RELEASE Spring Cloud版本:Greenwich.SR1 ...

  6. 推荐几个Spring Cloud学习资料

    研究Spring Cloud也有一段时间了,手头上有一点收集的资料,分享给小伙伴们学习. 博客 1.跟我学Spring Cloud 2.周立|Spring Cloud 3.Spring Cloud基础 ...

  7. .net core+Spring Cloud学习之路 二

    前言: 原本计划这次写一下搭建eureka群集.但是发现上次写的只是服务的注册,忘了写服务的发现,所以这次先把服务发现补上去. 我们基于上篇文章,再新建两个.net core web api项目,分别 ...

  8. .net core+Spring Cloud学习之路 一

    文章开头唠叨两句. 2019年了,而自己参加工作也两年有余了,用一个词来概括这两年多的生活,就是:“碌碌无为”. 也不能说一点收获都没有,但是很少.2019来了,我立志要打破现状,改变自己,突破自我. ...

  9. spring cloud学习填坑笔记

    最近在学习spring cloud,由于学习资料具有普遍性,部分应个人原因导致的小细节问题,往往很难找到解决的办法.这特别记录一下自己遇到的一些问题. 一.eureka-server加入securit ...

随机推荐

  1. VirtualBox虚拟机与主机互通,并且虚拟机又能上网配置

    1.在Virtualbox 的全局模式下建立host-only网络,完成之后在网络邻居的属性中会出现本地连接和virtualbox host-only ethernet 连接 2.点击本地连接的属性, ...

  2. 《死磕 Elasticsearch 方法论》:普通程序员高效精进的 10 大狠招!(完整版)

    原文:<死磕 Elasticsearch 方法论>:普通程序员高效精进的 10 大狠招!(完整版) 版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链 ...

  3. [译]理解 SwiftUI 里的属性装饰器@State, @Binding, @ObservedObject, @EnvironmentObject

    原文地址:https://mecid.github.io/2019/06/12/understanding-property-wrappers-in-swiftui/ @States 通过使用 @St ...

  4. ll字段 详解 文件权限

    文件类型和权限 硬链接总数 属主用户名 属组组名 文件大小(字节) 上次修改时间 文件/目录名 drwxr-xr-x 15 lb lb 4096 10月 19 01:11 ./ drwxr-xr-x ...

  5. oracle常用操作方法

    ---oracle创建数据库,基于plsqldev工具 1.创建表空间,创建空内容的物理文件create tablespace db_test --表空间名 datafile 'D:\test.dbf ...

  6. 029:url标签使用详解

    url标签使用详解: 在模版中,我们经常要写一些 url ,比如某个 a 标签中需要定义 href 属性.当然如果通过硬编码的方式直接将这个 url 写死在里面也是可以的.但是这样对于以后项目维护可能 ...

  7. Centos6安装mysql

    此处安装的是MariaDB,介绍如下: MariaDB数据库管理系统是MySQL的一个分支,主要由开源社区在维护,采用GPL授权许可. 开发这个分支的原因之一是:甲骨文公司收购了MySQL后,有将My ...

  8. 关于VS调试

    环境配置始终是我的弱项,碰到关于环境配置的问题就各种束手无策.但是这种事情,不能总凑合着,尤其你进不去环境或者没法调试的时候,代码写的多漂亮都没用.下面就来说一下最近关于调试的了解. 首先我们现在的项 ...

  9. python学习笔记(十二)随机数模块

    import random,string print(random.randint(1,199))#1-199随机取一个整数,包含199 print(string.digits)#所有的数字0-9 p ...

  10. Python_008(文件操作)

    一.文件操作 1.只读操作 f = open("taibai.txt",mode = "r",encoding = "utf-8" s = ...