通过上一节(zuul的各种配置)的学习,我们学会了zuul路由的各种配置,这一节我们来实现一下zuul的过滤器功能。那么为什么需要用到zuul的过滤器呢?我们知道zuul是我们实现外部系统统一访问的入口,那么我们就可以在 zuul 上实现 api的鉴权操作,实现微服务的统一鉴权、给微服务的响应增加额外的响应头等。
实现功能
1、在网关增加一个 pre 类型的过滤器完成一个简单的权限的校验
2、在网关增加一个 post 类型的过滤器完成增加一个相应头
3、禁用某个过滤器
代码结构
eureka-server |- 服务注册中心 zuul product-provider-8202 product-provider-8203 |- 服务提供者 product-consumer-8201 |- 服务消费者 product-gateway-filters-8205 |- 网关程序,演示 过滤器 的使用
代码和上一节的代码差不多,只是新建了一个网关程序,在网关中增加了过滤器。
zuul过滤器的四种类型
pre:
这种类型的过滤器在请求被路由到具体的服务之前进行调用,这个时候我们就可以进行权限的验证等等
route:
这种类型的过滤器将请求路由到具体的微服务。
post:
路由到微服务之后的处理,比如操作响应(Response),增加相应头、输出额外的内容
error:
当pre、route、post阶段发生异常时进行异常的处理
过滤器中各个方法的含义
@Override public String filterType() { } @Override public int filterOrder() { } @Override public boolean shouldFilter() { } @Override public Object run() { return null; }
filterType:
|- 表示过滤器的类型,即在那个阶段拦截,可以使用 FilterConstants 中的常量
filterOrder:
|- 过滤器的顺序,在同一组类型的过滤器中返回的值越小,越早执行。
>> pre 类型建议在 FilterConstants.PRE_DECORATION_FILTER_ORDER 之前执行
>> post 类型建议在 FilterConstants.SEND_RESPONSE_FILTER_ORDER 之前执行
shouldFilter:
|- true: 表示该过滤器执行 false:表示不执行该过滤器
run:
|- 执行具体的过滤器逻辑,返回值一般返回 null 即可。
在过滤器中,如果当前请求不合法,可以跑出异常或设置 RequestContext.getCurrentContext().setSendZuulResponse(false) 来阻止 route 类型的过滤器执行。
zuul过滤器的生命周期
一、官网zuul的请求生命周期图
解释:从上图可以看出,一次请求先经过 pre或 custom过滤器进行请求的预处理,然后通过 route 类型的过滤器将请求路由到据图的微服务,最终经过 post 类型的过滤器对响应数据进行处理。这三个阶段(pre、route、post)过程中发生了异常都会经过 error 类型的过滤器进行处理,error 处理完之后再次经过 post 类型的过滤器进行处理。
二、从代码(ZuulServlet)中看各个过滤器执行的顺序
代码编写
一、注册中心、服务提供者、服务消费者(略)
二、网关程序编写
①、引入 zuul 的依赖
<dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-zuul</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies>
② 启动类上增加 @EnableZuulProxy 注解
@SpringBootApplication @EnableZuulProxy @EnableDiscoveryClient public class ProductGatewayZuulApplication8205 { public static void main(String[] args) { SpringApplication.run(ProductGatewayZuulApplication8205.class, args); } }
③、编写 pre 过滤器,进行权限判断
只要能从 request 中 获取到 token 的参数的值,那么认为通过,否则不通过。
package com.huan.study.zuul.filter; import com.netflix.zuul.ZuulFilter; import com.netflix.zuul.context.RequestContext; import com.netflix.zuul.exception.ZuulException; import org.apache.commons.lang.StringUtils; import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants; import org.springframework.cloud.netflix.zuul.util.ZuulRuntimeException; import org.springframework.http.HttpStatus; import org.springframework.stereotype.Component; import javax.servlet.http.HttpServletRequest; /** * Token 认证前置过滤器 * * @author huan.fu * @date 2018/6/12 - 16:34 */ @Component public class TokenAuthenticationFilter extends ZuulFilter { private static final String TOKEN_PARAMETER = "token"; @Override public String filterType() { // pre 类型的过滤器 return FilterConstants.PRE_TYPE; } @Override public int filterOrder() { // token 检验应该放在第一位来进行校验,因此需要放在最前面 return FilterConstants.SERVLET_DETECTION_FILTER_ORDER - 1; } @Override public boolean shouldFilter() { // 过滤器是否应该执行, true:表示应该执行 false:表示跳过这个过滤器执行 return true; } @Override public Object run() { RequestContext requestContext = RequestContext.getCurrentContext(); // 获取到 request HttpServletRequest request = requestContext.getRequest(); // 判断请求参数中是否存在 token 参数 String token = request.getParameter(TOKEN_PARAMETER); if (StringUtils.isBlank(token)) { // 不进行路由 ===> 即 route 类型的过滤器不执行 requestContext.setSendZuulResponse(false); throw new ZuulRuntimeException(new ZuulException(this.filterType() + ":" + this.getClass().getSimpleName(), HttpStatus.UNAUTHORIZED.value(), "token参数不可为空")); } return null; } }
注意:
1、RequestContext 为一个 ConcurrentHashMap, 并且里面的值是从 ThreadLocal 中获取的
2、可以从RequestContext中获取到 request 和 response 等等
3、requestContext.setSendZuulResponse(false) 会导致 route 类型的过滤器不进行执行。
4、如果不想自己写 error 类型的过滤器,那么默认由 SendErrorFilter 进行处理异常,如果我们想返回一个 401 的状态码给前台,出错的地方可以跑出一个 ZuulRuntimeException.
5、自己写的 过滤器 需要被 Spring 管理即可。
④、编写一个 post 类型的过滤器,增加一个额外的响应头
添加一个 new-header 的响应头
package com.huan.study.zuul.filter; import com.netflix.zuul.ZuulFilter; import com.netflix.zuul.context.RequestContext; import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants; import org.springframework.stereotype.Component; import javax.servlet.http.HttpServletResponse; /** * 添加一个新的相应头 * * @author huan.fu * @date 2018/6/12 - 18:01 */ @Component public class AddNewHeaderFilter extends ZuulFilter { @Override public String filterType() { return FilterConstants.POST_TYPE; } @Override public int filterOrder() { return FilterConstants.SEND_RESPONSE_FILTER_ORDER - 1; } @Override public boolean shouldFilter() { return true; } @Override public Object run() { RequestContext requestContext = RequestContext.getCurrentContext(); HttpServletResponse response = requestContext.getResponse(); response.addHeader("new-header", "new-header"); return null; } }
⑤、运行结果
禁用过滤器
有些时候我们可能想禁用某一类型的过滤器,比如异常返回的过滤器,每个公司可能都有自己异常返回的一套风格,如果我们不想使用 Zuul 默认的异常过滤器,那么就可以禁用掉这个过滤器。
语法格式:
zuul.<SimpleClassName>.<filterType>.disable=true
禁用 SendErrorFilter
zuul:
SendErrorFilter:
error:
disable: true
访问网关服务的 /filters 端点,看是否禁用掉
完整代码
网关层的代码: https://gitee.com/huan1993/spring-cloud-parent/tree/master/zuul
网关过滤器的代码: https://gitee.com/huan1993/spring-cloud-parent/tree/master/zuul/product-gateway-filters-8205
相关推荐
总之,通过自定义Zuul过滤器,我们可以灵活地对服务的响应进行处理,满足各种业务需求。无论是对敏感信息的加密、响应头的修改,还是错误处理,都可以通过编写相应的过滤器来实现。理解并熟练运用Zuul过滤器机制,...
本文将深入探讨Zuul过滤器,包括其类型、生命周期、编写方法以及如何禁用和自定义过滤器。 1. **Zuul过滤器类型与请求生命周期** Zuul过滤器是实现其核心功能的关键,分为四类: - **PRE过滤器**:在请求被路由...
1. **创建自定义过滤器**:编写一个实现了 `ZuulFilter` 接口的类,并重写 `filterType()`、`filterOrder()`、`shouldFilter()` 和 `run()` 方法。`filterType()` 定义过滤器类型,`filterOrder()` 设置执行顺序,`...
Zuul过滤器的应用场景非常广泛,例如,身份验证、权限控制、日志记录、限流熔断等。在实际开发中,我们可以根据不同的需求,选择合适的过滤器类型和执行顺序,以达到不同的业务逻辑。 四、结语 本文主要介绍了...
3. **Zuul过滤器** - 预过滤器(Pre Filters):在路由之前执行,常用于身份验证、限流等操作。 - 路由过滤器(Routing Filters):根据请求路由到对应的后端服务。 - 执行过滤器(Route Filters):在路由之后,...
- `ZuulFilter.java`:自定义过滤器示例,包括过滤器的生命周期方法(run 方法)以及过滤器类型定义(filterType 和 filterOrder)。 - `application.yml`:配置文件,定义路由规则和其他配置,如过滤器配置、...
Spring Cloud Zuul是Spring Cloud生态系统中的一个组件,它充当了一个边缘服务或API网关的角色。Zuul的主要职责包括路由转发、...同时,过滤器的执行性能也会影响整个系统的性能,因此在编写过滤器时要注重效率和优化。
例如,创建自定义全局过滤器类,继承`AbstractGatewayFilterFactory`,然后在`apply()`方法中编写鉴权逻辑。同时,可能还会包含配置文件(如`application.yml`或`application.properties`),用于设置路由和过滤器的...
3. **自定义过滤器**:如果需要定制化的过滤器逻辑,可以在项目中编写自定义的 Filter 类,实现 Spring Cloud Gateway 所需的接口。 4. **POM 文件**:依赖管理,包含了 Spring Cloud Gateway 相关的依赖以及可能的...
- **过滤器(Filter)**:在请求被路由之前或之后执行的操作,例如添加请求头、修改响应体等。 Spring Cloud Gateway通过这些核心概念,提供了高度可定制化的路由规则和过滤器链,使得开发者能够轻松地构建和管理...
- **过滤器**:Zuul支持多种类型的过滤器,包括预处理、后处理、路由过滤器等。 - **动态路由**:通过Zuul的路由功能,可以实现动态路由,根据不同的条件将请求路由到不同的服务。 6. **Config** - **分布式配置...
使用Spring Cloud Netflix的Zuul组件实现网关功能,通过自定义过滤器(Filter)来增强网关的能力。 - **动态路由**:根据请求的路径、HTTP头部等信息将请求转发至正确的微服务。 - **限流与容错**:防止过大的流量...