惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

IT之家
IT之家
Recent Announcements
Recent Announcements
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
The GitHub Blog
The GitHub Blog
MyScale Blog
MyScale Blog
爱范儿
爱范儿
GbyAI
GbyAI
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
美团技术团队
Y
Y Combinator Blog
博客园 - 叶小钗
Apple Machine Learning Research
Apple Machine Learning Research
Martin Fowler
Martin Fowler
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
罗磊的独立博客
M
MIT News - Artificial intelligence
博客园 - Franky
V
Visual Studio Blog
I
InfoQ
V
V2EX
Hugging Face - Blog
Hugging Face - Blog
腾讯CDC
博客园 - 司徒正美
L
LangChain Blog

博客园 - 立3807

ROS 系统架构及概念 ROS 在 Ubuntu 18.04 安装 利用 Skywalking 搭建 APM(应用性能管理)— 安装与配置 elasticsearch 集群搭建及启动常见错误 Git 基本操作 Git 环境配置 Git 安装 Git 基础和原理 Spring Cloud(Dalston.SR5)--Config 集群配置中心-加解密 Spring Cloud(Dalston.SR5)--Config 集群配置中心-刷新配置 Java NIO 概述 Spring Boot - AOP(面向切面)-切入点表达式 Spring Boot - AMQP 消息中间件 Spring Boot - AOP(面向切面) Spring Boot - 基础 POM 文件 Spring Boot - 配置介绍 Spring Boot - 项目构建与解析 Mycat 镜像-创建 Docker 镜像 Spring Cloud(Dalston.SR5)--Config 集群配置中心 Spring Cloud(Dalston.SR5)--Zuul 网关-Hystrix 回退
Spring Cloud(Dalston.SR5)--Zuul 网关-过滤器
立3807 · 2018-04-23 · via 博客园 - 立3807

Spring Cloud 为 HTTP 请求的各个阶段提供了多个过滤器,这些过滤器的执行顺序由各自提供的一个 int 值决定,提供的值越小则优先级越高,默认的过滤器及优先级如下:

自定义过滤器

在默认过滤器的基础上,我们可以实现自己的自定义过滤器,自定义过滤器需要继承 com.netflix.zuul.ZuulFilter 类,并实现相关方法,说明如下:

  • filterType:该函数需要返回一个字符串来代表过滤器的类型,而这个类型就是在HTTP请求过程中定义的各个阶段。在Zuul中默认定义了四种不同生命周期的过滤器类型,具体如下:

    • pre:可以在请求被路由之前调用
    • routing:在路由请求时候被调用
    • post:在routing和error过滤器之后被调用
    • error:处理请求时发生错误时被调用
  • filterOrder:通过int值来定义过滤器的执行顺序,数值越小优先级越高
  • shouldFilter:返回一个boolean类型来判断该过滤器是否要执行。我们可以通过此方法来指定过滤器的有效范围。
  • run:过滤器的具体逻辑。在该函数中,我们可以实现自定义的过滤逻辑,来确定是否要拦截当前的请求,不对其进行后续的路由,或是在请求路由返回结果之后,对处理结果做一些加工等

Zuul 默认定义了四个不同的过滤器类型,它们覆盖了一个外部HTTP请求到达API网关,直到返回请求结果的全部生命周期。下图源自Zuul的官方WIKI中关于请求生命周期的图解,它描述了一个HTTP请求到达API网关之后,如何在各个不同类型的过滤器之间流转的详细过程如下:

我们可以看到,当外部 HTTP 请求到达 API 网关服务的时候,首先它会进入第一个阶段 pre,在这里它会被pre 类型的过滤器进行处理,该类型的过滤器主要目的是在进行请求路由之前做一些前置加工,比如请求的校验等。

在完成了 pre 类型的过滤器处理之后,请求进入第二个阶段 routing,也就是之前说的路由请求转发阶段,请求将会被 routing 类型过滤器处理,这里的具体处理内容就是将外部请求转发到具体服务实例上去的过程,当服务实例将请求结果都返回之后,routing 阶段完成,请求进入第三个阶段 post,此时请求将会被 post 类型的过滤器进行处理,这些过滤器在处理的时候不仅可以获取到请求信息,还能获取到服务实例的返回信息,所以在 post 类型的过滤器中,我们可以对处理结果进行一些加工或转换等内容。

另外,还有一个特殊的阶段error,该阶段只有在上述三个阶段中发生异常的时候才会触发,但是它的最后流向还是post类型的过滤器,因为它需要通过post过滤器将最终结果返回给请求客户端。

过滤器示例

  • 验证过滤器

    该过滤器会在 pre 阶段执行,并且其优先级为 1 在包装请求体后执行,其 shouldFilter 返回 true 表示任何情况都执行该过滤器,在 run 方法通过获取 HttpServletRequest 示例获取请求参数并进行验证,在验证失败的时候通过设置 HttpServletResponse 示例和 setSendZuulResponse(false) 来直接返回响应信息,而不进行后续过滤器处理。

    package org.lixue.zuul;

    import com.netflix.zuul.ZuulFilter;

    import com.netflix.zuul.context.RequestContext;

    import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants;

    import javax.servlet.http.HttpServletRequest;

    import javax.servlet.http.HttpServletResponse;

    import java.io.IOException;

    public class TokenPreZullFilter extends ZuulFilter{

    @Override

    public String filterType(){

    return FilterConstants.PRE_TYPE;

    }

    @Override

    public int filterOrder(){

    return 1;

    }

    @Override

    public boolean shouldFilter(){

    return true;

    }

    @Override

    public Object run(){

    RequestContext ctx=RequestContext.getCurrentContext();

    HttpServletRequest request=ctx.getRequest();

    System.out.println(String.format("%s request to %s",request.getMethod(),request.getRequestURL().toString()));

    String token=request.getParameter("token");

    System.out.println("token:"+token);

    if(token==null||!token.equals("success_token")){

    //认证失败

    System.out.println("token验证失败");

    HttpServletResponse response=ctx.getResponse();

    response.setCharacterEncoding("utf-8");//设置字符集

    response.setContentType("text/html;charset=utf-8");//设置相应格式

    response.setStatus(401);

    ctx.setSendZuulResponse(false);//不进行路由

    try{

    response.getWriter().write("token验证失败");//响应体

    }catch(IOExceptione){

    System.out.println("responseio异常");

    e.printStackTrace();

    }

    ctx.setResponse(response);

    return null;

    }

    System.out.println("token验证成功");

    return null;

    }

    }

  • 过滤器配置类

    为了让 Spring 容器知道过滤器的存在,需要对该类进行配置,创建过滤器配置类,使用注解 @Configuration 标注类,并使用 @Bean 注解标注返回过滤器的方法。

    package org.lixue.zuul;

    import org.springframework.context.annotation.Bean;

    import org.springframework.context.annotation.Configuration;

    @Configuration

    public class ZuulFilterConfiguration{

    @Bean

    public TokenPreZullFilter tokenPreZullFilter(){

    return newTokenPreZullFilter();

    }

    }

  • 测试验证

    项目依赖一个 eureka-sserver、service-provider 服务,首先启动 eureka-server 和 service-provider 服务,然后启动 spring-cloud-zuul-microservices 服务,访问 http://localhost:9200/hello/speaks?names=123&token=success_token 地址,可以看到能正常返回,如下:

    {"123":"Hello World 123 Port=8080"}

    修改访问地址,移除 token 参数或者修改参数值 http://localhost:9200/hello/speaks?names=123&token=success_token999 这时会返回 token 验证失败的错误,并且没有执行后续的路由处理。

本文版权归作者 李雪(博客地址:https://www.cnblogs.wiki)所有,欢迎转载和商用,请在文章页面明显位置给出原文链接并保留此段声明,否则保留追究法律责任的权利,其他事项,可留言咨询。