本文转自:http://blog.csdn.net/liuchuanhong1/article/details/62236793

关于网关的作用,这里就不再次赘述了,我们今天的重点是zuul的Filter。通过Filter,我们可以实现安全控制,比如,只有请求参数中有用户名和密码的客户端才能访问服务端的资源。那么如何来实现Filter了?

要想实现Filter,需要以下几个步骤:

1、继承ZuulFilter类,为了验证Filter的特性,我们这里创建3个Filter

根据用户名来过滤

  1. package com.chhliu.springcloud.zuul;
  2.  
  3. import javax.servlet.http.HttpServletRequest;
  4.  
  5. import com.netflix.zuul.ZuulFilter;
  6. import com.netflix.zuul.context.RequestContext;
  7.  
  8. public class AccessUserNameFilter extends ZuulFilter {
  9. @Override
  10. public Object run() {
  11. RequestContext ctx = RequestContext.getCurrentContext();
  12. HttpServletRequest request = ctx.getRequest();
  13.  
  14. System.out.println(String.format("%s AccessUserNameFilter request to %s", request.getMethod(), request.getRequestURL().toString()));
  15.  
  16. String username = request.getParameter("username");// 获取请求的参数
  17. if(null != username && username.equals("chhliu")) {// 如果请求的参数不为空,且值为chhliu时,则通过
  18. ctx.setSendZuulResponse(true);// 对该请求进行路由
  19. ctx.setResponseStatusCode(200);
  20. ctx.set("isSuccess", true);// 设值,让下一个Filter看到上一个Filter的状态
  21. return null;
  22. }else{
  23. ctx.setSendZuulResponse(false);// 过滤该请求,不对其进行路由
  24. ctx.setResponseStatusCode(401);// 返回错误码
  25. ctx.setResponseBody("{\"result\":\"username is not correct!\"}");// 返回错误内容
  26. ctx.set("isSuccess", false);
  27. return null;
  28. }
  29. }
  30.  
  31. @Override
  32. public boolean shouldFilter() {
  33. return true;// 是否执行该过滤器,此处为true,说明需要过滤
  34. }
  35.  
  36. @Override
  37. public int filterOrder() {
  38. return 0;// 优先级为0,数字越大,优先级越低
  39. }
  40.  
  41. @Override
  42. public String filterType() {
  43. return "pre";// 前置过滤器
  44. }
  45. }

通过继承ZuulFilter然后覆写上面的4个方法,就可以实现一个简单的过滤器,下面就相关注意点进行说明

filterType:返回一个字符串代表过滤器的类型,在zuul中定义了四种不同生命周期的过滤器类型,具体如下:

  • pre:可以在请求被路由之前调用
  • route:在路由请求时候被调用
  • post:在route和error过滤器之后被调用
  • error:处理请求时发生错误时被调用

Zuul的主要请求生命周期包括“pre”,“route”和“post”等阶段。对于每个请求,都会运行具有这些类型的所有过滤器。

filterOrder:通过int值来定义过滤器的执行顺序

shouldFilter:返回一个boolean类型来判断该过滤器是否要执行,所以通过此函数可实现过滤器的开关。在上例中,我们直接返回true,所以该过滤器总是生效

run:过滤器的具体逻辑。需要注意,这里我们通过ctx.setSendZuulResponse(false)令zuul过滤该请求,不对其进行路由,然后通过ctx.setResponseStatusCode(401)设置了其返回的错误码

过滤器间的协调
    过滤器没有直接的方式来访问对方。 它们可以使用RequestContext共享状态,这是一个类似Map的结构,具有一些显式访问器方法用于被认为是Zuul的原语,内部是使用ThreadLocal实现的,有兴趣的同学可以看下源码。

再建一个过滤器,根据密码来过滤:

  1. package com.chhliu.springcloud.zuul;
  2.  
  3. import javax.servlet.http.HttpServletRequest;
  4.  
  5. import com.netflix.zuul.ZuulFilter;
  6. import com.netflix.zuul.context.RequestContext;
  7.  
  8. public class AccessPasswordFilter extends ZuulFilter {
  9.  
  10. @Override
  11. public Object run() {
  12. RequestContext ctx = RequestContext.getCurrentContext();
  13. HttpServletRequest request = ctx.getRequest();
  14.  
  15. System.out.println(String.format("%s AccessPasswordFilter request to %s", request.getMethod(), request.getRequestURL().toString()));
  16.  
  17. String username = request.getParameter("password");
  18. if(null != username && username.equals("123456")) {
  19. ctx.setSendZuulResponse(true);
  20. ctx.setResponseStatusCode(200);
  21. ctx.set("isSuccess", true);
  22. return null;
  23. }else{
  24. ctx.setSendZuulResponse(false);
  25. ctx.setResponseStatusCode(401);
  26. ctx.setResponseBody("{\"result\":\"password is not correct!\"}");
  27. ctx.set("isSuccess", false);
  28. return null;
  29. }
  30. }
  31.  
  32. @Override
  33. public boolean shouldFilter() {
  34. RequestContext ctx = RequestContext.getCurrentContext();
  35. return (boolean) ctx.get("isSuccess");// 如果前一个过滤器的结果为true,则说明上一个过滤器成功了,需要进入当前的过滤,如果前一个过滤器的结果为false,则说明上一个过滤器没有成功,则无需进行下面的过滤动作了,直接跳过后面的所有过滤器并返回结果
  36. }
  37.  
  38. @Override
  39. public int filterOrder() {
  40. return 1; // 优先级设置为1
  41. }
  42.  
  43. @Override
  44. public String filterType() {
  45. return "pre";
  46. }
  47. }

最后建一个post过滤器

  1. package com.chhliu.springcloud.zuul;
  2.  
  3. import javax.servlet.http.HttpServletRequest;
  4.  
  5. import com.netflix.zuul.ZuulFilter;
  6. import com.netflix.zuul.context.RequestContext;
  7.  
  8. public class AccessTokenFilter extends ZuulFilter {
  9. @Override
  10. public Object run() {
  11. RequestContext ctx = RequestContext.getCurrentContext();
  12. HttpServletRequest request = ctx.getRequest();
  13.  
  14. System.out.println(String.format("%s AccessTokenFilter request to %s", request.getMethod(),
  15. request.getRequestURL().toString()));
  16.  
  17. ctx.setSendZuulResponse(true);
  18. ctx.setResponseStatusCode(200);
  19. ctx.setResponseBody("{\"name\":\"chhliu\"}");// 输出最终结果
  20. return null;
  21. }
  22.  
  23. @Override
  24. public boolean shouldFilter() {
  25. return true;
  26. }
  27.  
  28. @Override
  29. public int filterOrder() {
  30. return 0;
  31. }
  32.  
  33. @Override
  34. public String filterType() {
  35. return "post";// 在请求被处理之后,会进入该过滤器
  36. }
  37. }

2、在主类中,先开启前面的两个过滤器

3、输入请求,验证

(1)请求为:http://localhost:8768/h2service/user/1?username=chhliu

测试结果为:

  1. {"result":"password is not correct!"}

控制台打印结果

  1. GET AccessUserNameFilter request to http://localhost:8768/h2service/user/1
  2. GET AccessPasswordFilter request to http://localhost:8768/h2service/user/1

通过了AccessUserNameFilter过滤器,在验证AccessPasswordFilter过滤器的时候失败了

后台无sql打印,说明请求没有被路由

(2)请求为:http://localhost:8768/h2service/user/1?password=123456

测试结果为:

  1. {"result":"username is not correct!"}

控制台打印结果:

  1. GET AccessUserNameFilter request to http://localhost:8768/h2service/user/1

说明到了AccessUserNameFilter过滤器,但是没有到AccessPasswordFilter过滤器,因为AccessUserNameFilter过滤器的优先级高一些,会先执行,在执行的时候,发现过滤条件不符合,于是跳过了后面所有的过滤器,并返回结果

后台无sql打印,说明请求没有被路由

(3)请求为:http://localhost:8768/h2service/user/1?password=123456&username=chhliu

测试结果为:

控制台打印的结果:

  1. GET AccessUserNameFilter request to http://localhost:8768/h2service/user/1
  2. GET AccessPasswordFilter request to http://localhost:8768/h2service/user/1

说明是先执行了AccessUserNameFilter然后才执行AccessPasswordFilter这也和我们前面说的order的值越小,优先级越高是吻合的。

同时被请求的服务有sql输出:

  1. Hibernate: select user0_.id as id1_0_0_, user0_.age as age2_0_0_, user0_.balance as balance3_0_0_, user0_.name as name4_0_0_, user0_.username as username5_0_0_ from user user0_ where user0_.id=?

说明请求被路由了。

4、开启post过滤器,再跑一次

测试结果:发现post过滤器是最后执行的,尽管它的优先级为0

关于zuul的Filter的生命周期,见下图

注:上图有个小错误,routing应该是route

5、拓展

zuul还提供了一类特殊的过滤器,分别为:StaticResponseFilter和SurgicalDebugFilter

StaticResponseFilter:StaticResponseFilter允许从Zuul本身生成响应,而不是将请求转发到源。

SurgicalDebugFilter:SurgicalDebugFilter允许将特定请求路由到分隔的调试集群或主机。

spring cloud-zuul的Filter详解(十一)的更多相关文章

  1. Spring Cloud Zuul 限流详解(附源码)(转)

    在高并发的应用中,限流往往是一个绕不开的话题.本文详细探讨在Spring Cloud中如何实现限流. 在 Zuul 上实现限流是个不错的选择,只需要编写一个过滤器就可以了,关键在于如何实现限流的算法. ...

  2. Spring Cloud(十二):Spring Cloud Zuul 限流详解(附源码)(转)

    前面已经介绍了很多zuul的功能,本篇继续介绍它的另一大功能.在高并发的应用中,限流往往是一个绕不开的话题.本文详细探讨在Spring Cloud中如何实现限流. 在 Zuul 上实现限流是个不错的选 ...

  3. Spring Cloud Zuul之ZuulFilter详解

    简介 Spring Cloud Zuul网关在整个微服务体系中肩负对外开放接口.请求拦截.路由转发等作用,其核心处理则是ZuulFilter ZuulFilter部分源码 Zuul Filter全部继 ...

  4. Spring Cloud Zuul网关 Filter、熔断、重试、高可用的使用方式。

    时间过的很快,写springcloud(十):服务网关zuul初级篇还在半年前,现在已经是2018年了,我们继续探讨Zuul更高级的使用方式. 上篇文章主要介绍了Zuul网关使用模式,以及自动转发机制 ...

  5. Zuul之Filter详解

    Zuul详解 官方文档:https://github.com/Netflix/zuul/wiki/How-it-Works Zuul的中心是一系列过滤器,能够在HTTP请求和响应的路由过程中执行一系列 ...

  6. 笔记:Spring Cloud Ribbon 客户端配置详解

    自动化配置 由于 Ribbon 中定义的每一个接口都有多种不同的策略实现,同时这些接口之间又有一定的依赖关系,Spring Cloud Ribbon 中的自动化配置能够很方便的自动化构建接口的具体实现 ...

  7. Spring Cloud Eureka 常用配置详解,建议收藏!

    前几天,栈长分享了 <Spring Cloud Eureka 注册中心集群搭建,Greenwich 最新版!>,今天来分享下 Spring Cloud Eureka 常用的一些参数配置及说 ...

  8. Spring Cloud(十一):Spring Cloud Zuul网关 Filter、熔断、重试、高可用的使用方式

    上篇文章主要介绍了Zuul网关使用模式,以及自动转发机制,但其实Zuul还有更多的应用场景,比如:鉴权.流量转发.请求统计等等,这些功能都可以使用Zuul来实现. Zuul的核心 Filter是Zuu ...

  9. spring cloud深入学习(十二)-----Spring Cloud Zuul网关 Filter、熔断、重试、高可用的使用方式

    Zuul的核心 Filter是Zuul的核心,用来实现对外服务的控制.Filter的生命周期有4个,分别是“PRE”.“ROUTING”.“POST”.“ERROR”,整个生命周期可以用下图来表示. ...

  10. Spring Cloud学习 之 Spring Cloud Hystrix(使用详解)

    文章目录 创建请求命令: 定义服务降级: 异常处理: 异常传播: 异常获取: 命令名称,分组以及线程池划分: 创建请求命令: ​ Hystrix命令就是我们之前说的HystrixCommand,它用来 ...

随机推荐

  1. ansible使用1

    常用软件安装及使用目录   ansible软件2 ### ansible软件部署安装需求#### 01. 需要有epel源 系统yum源(base epel--pip gem) sshpass---e ...

  2. 44 道 JavaScript 难题(JavaScript Puzzlers!)

    JavaScript Puzzlers原文 1. ["1", "2", "3"].map(parseInt) 答案:[1, NaN, NaN ...

  3. (第二周)scrum站立会议

    敏捷流程scrum中的很重要的一个制度之一每日站立会议 了解的内容: 问题:为啥不用email汇报代替每日会议? E-mail不能取代每日会议,E-mail只会增加沟通成本,而且不能提供细节信息或者给 ...

  4. Scrum Meeting 13 -2014.11.19

    最近数据库和编译的实验课也开始了,大家晚上的时间直接被砍掉了大部分. 希望大家能顺利完成项目吧.剩下时间也不多了,如果程序还存在一些特别的问题和需要优化修改的地方也应该考虑留到下阶段进行了. Memb ...

  5. 2-Nineth Scrum Meeting20151209

    任务分配 闫昊: 今日完成:商讨如何迁移ios代码到android平台. 明日任务:请假.(编译) 唐彬: 今日完成:商讨如何迁移ios代码到android平台. 明日任务:请假.(编译) 史烨轩: ...

  6. 2018-2019-20172321 《Java软件结构与数据结构》第七周学习总结

    2018-2019-20172321 <Java软件结构与数据结构>第七周学习总结 教材学习内容总结 第11章 二叉查找树 一.概述 二叉查找树是一种含有附加属性的二叉树,该属性即其左孩子 ...

  7. WebGL学习笔记七点一

    第六章讲的是一些GL的一些语法,前面已经涉及,学习时直接跳过,来看第七章,第七章是真正意义的三维立体的出现,其实图形绘制方法是差不多的,就是Z坐标此时不再为0,所以很容易能构造出一些立体图形,但是立体 ...

  8. UTC时间与北京时间

    经常混淆于此,特地研究了一下,记录在此以备忘. 整个地球分为二十四时区,每个时区都有自己的本地时间.在国际无线电通信场合,为了统一起见,使用一个统一的时间,称为通用协调时(UTC, Universal ...

  9. C++模板常用功能讲解

    前言 泛型编程是C++继面向对象编程之后的又一个重点,是为了编写与具体类型无关的代码.而模板是泛型编程的基础.模板简单来理解,可以看作是用宏来实现的,事实上确实有人用宏来实现了模板类似的功能.模板,也 ...

  10. [转帖]HTTPS的简单说明

    HTTPS(全称:Hyper Text Transfer Protocol over SecureSocket Layer),是以安全为目标的 HTTP 通道,简单讲是 HTTP 的安全版,即 HTT ...