springcloud 入门系列(九) zuul过滤器

昨天了解了zuul的API网关的搭建,以及路由的配置等知识,今天来了解zuul 的过滤器部分。

过滤器的功能是对外部访问,处理请求的过程进行干预,是实现外部请求访问统一入口的基础,他包含了对请求的校验,服务聚合等基础功能,实际在路由映射和请求转发都是由几个不同的过滤器完成的。下面我们先来看下过滤器的接口定义:

 abstract public String filterType(); abstract public int filterOrder(); boolean shouldFilter();   Object run() throws ZuulException;

zuul 定义了四种不同生命周期的过滤器,如下:

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

routing: 在路由被请求时调用

post:在routing 和 error 之后被调用

error: 在处理请求发送错误时被调用

 

filterOrder(): 通过int 值来指定过滤器执行顺序,数值越小,优先级越高

shouldFilter(): 返回布尔值,来进行判断是否需要质性过滤器。

run(): 过滤器的具体逻辑。

下图是请求的在过滤器中的流转示意图:

 

我们看到请求进来后,首先会到“pre” 类型过滤器,这个过滤器主要做一些校验性质的工作,通过后会进入到“routing”阶段,也就是路由请求转发阶段,会把请求转发到具体的服务器上,服务请求处理完请求后进入“post” 阶段,在这里我们可以拿到请求结果,可以做一些请求结果的统一封装之类的工作,最后还有一个特殊的阶段“error” 阶段,改阶段只有在上述三个阶段发生请求异常才会进入“error”过滤器,他最后的流向还是post,因为最终我们还是需要给用户响应的。

核心过滤器

springcloud zuul 为了简化API网关组件的使用,在http请求声明周期的各个阶段默认实现了一批核心过滤器,他们会在API 网关服务被启动时自动加载和启动,如图:

下面是一些核心过滤器的介绍:

pre过滤器

ServletDetectionFilter:他的执行顺序是-3,是最先被执行的过滤器,该过滤器主要用来探测请求是通过spring 的 DispatcherServlet 处理运行的还是通过ZuulServlet来处理的。

Servlet30WrapperFilter:执行顺序 -2,主要是将HttpServletRequest包装成Servlet30RequestWrapper对象。

FormBodyWrapperFilter:执行顺序 -1,主要目的是将符合要求的请求包装成FormBodyRequestWrapper.

DebugFilter: 执行顺序1,设置debug参数信息,以便后续debug过程能查看debug信息。

PreDecorationFilter:执行顺序是5,是pre阶段最后被执行的过滤器,该过滤器会判断当前请求上下文中是否存在forward.doserviceId参数,如果都不存在,那么它就会执行具体过滤器的操作(如果有一个存在的话,说明当前请求已经被处理过了,因为这二个信息就是根据当前请求的路由信息加载进来的)。而当它的具体操作内容就是为当前请求做一些预处理,比如说,进行路由规则的匹配,在请求上下文中设置该请求的基本信息以及将路由匹配结果等一些设置信息等,这些信息将是后续过滤器进行处理的重要依据,我们可以通过RequestContext.getCurrentContext()来访问这些信息。另外,我们还可以在该实现中找到对HTTP头请求进行处理的逻辑,其中包含了一些耳熟能详的头域,比如X-Forwarded-Host,X-Forwarded-Port。另外,对于这些头域是通过zuul.addProxyHeaders参数进行控制的,而这个参数默认值是true,所以zuul在请求跳转时默认会为请求增加X-Forwarded-*头域,包括X-Forwarded-Host,X-Forwarded-PortX-Forwarded-ForX-Forwarded-Prefix,X-Forwarded-Proto。也可以通过设置zuul.addProxyHeaders=false关闭对这些头域的添加动作。

route 过滤器

RibbonRoutingFilter:它的执行顺序为10,是route阶段的第一个执行的过滤器。该过滤器只对请求上下文中存在serviceId参数的请求进行处理,即只对通过serviceId配置路由规则的请求生效。而该过滤器的执行逻辑就是面向服务路由的核心,它通过使用ribbon和hystrix来向服务实例发起请求,并将服务实例的请求结果返回。

SimpleHostRoutingFilter:它的执行顺序为100,是route阶段的第二个执行的过滤器。该过滤器只对请求上下文存在routeHost参数的请求进行处理,即只对通过url配置路由规则的请求生效。而该过滤器的执行逻辑就是直接向routeHost参数的物理地址发起请求,从源码中我们可以知道该请求是直接通过httpclient包实现的,而没有使用Hystrix命令进行包装,所以这类请求并没有线程隔离和断路器的保护。

SendForwardFilter:它的执行顺序是500,是route阶段第三个执行的过滤器。该过滤器只对请求上下文中存在的forward.do参数进行处理请求,即用来处理路由规则中的forward本地跳转装配。

post过滤器

  • SendErrorFilter:它的执行顺序是0,是post阶段的第一个执行的过滤器。该过滤器仅在请求上下文中包含error.status_code参数(由之前执行的过滤器设置的错误编码)并且还没有被该过滤器处理过的时候执行。而该过滤器的具体逻辑就是利用上下文中的错误信息来组成一个forward到api网关/error错误端点的请求来产生错误响应。

SendErrorFilter的run方法

  • SendResponseFilter:它的执行顺序为1000,是post阶段最后执行的过滤器,该过滤器会检查请求上下文中是否包含请求响应相关的头信息,响应数据流或是响应体,只有在包含它们其中一个的时候执行处理逻辑。而该过滤器的处理逻辑就是利用上下文的响应信息来组织需要发送回客户端的响应内容。

下面我们开始上代码,创建一个“pre”的过滤器:

@Slf4j@Componentpublic class AccessFilter extends ZuulFilter {    @Override    public String filterType() {        return "pre";    }
    @Override    public int filterOrder() {        return 0;    }
    @Override    public boolean shouldFilter() {              return true;    }
    @Override    public Object run() {        RequestContext ctx = RequestContext.getCurrentContext();        HttpServletRequest request = ctx.getRequest();        log.info("send to:{}, request to-{}", request.getMethod(), request.getRequestURL());        Object accessToken = request.getParameter("accessToken");        if (!"GATEWAY".equals(accessToken)) {            log.warn("accessToken is empty!!!");            ctx.setSendZuulResponse(false);            ctx.getResponse().setContentType("text/html;charset=UTF-8");            ctx.setResponseBody("非法请求token!!!");            ctx.setResponseStatusCode(401);        }        return null;    }

我们只需要实现ZuulFilter 接口即可,并且声明为spring Bean,实现逻辑很简单,校验请求中是否带有accessToken请求参数,并且是否和预期的字符串“GATEWAY”相等,否则我们返回“401” 请求错误,我们启动项目,并且测试请求:http://localhost:8085/helloservice/refact/hello1?name=ethan&accessToken=GATEWAYs

看到请求被拦截了,并返回了响应的错误信息,再请求:

localhost:8085/helloservice/refact/hello1?name=ethan&accessToken=GATEWAY

请求被正确路由并返回了。至此zuul的过滤器部分结束,如有不对之处欢迎指正!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值