Zuul过滤器
zuul包含了对请求的路由和过滤两个功能,
- 路由功能负责将外部请求转发到具体的微服务实例上,是实现外部访问统一入口的基础
- 过滤器功能则负责对请求的处理过程进行干预,是实现请求校验、服务聚合等功能的基础
每一个进入Zuul的HTTP请求都会经过一系列的过滤器处理链得到请求响应并返回给客户端。
在Spring Cloud Zuul中实现的过滤器必须包含4个基本特征:
- 过滤类型
- 执行顺序
- 执行条件
- 具体操作
ZuulFilter是一个抽象类,并且实现IZuulFilter接口,filterType:该函数需要返回一个字符串来代表过滤器的类型,而这个类型就是在HTTP请求过程中定义的各个阶段。
在Zuul中默认定义四种不同生命周期的过滤器类型,具体如下:
pre:在请求被路由之前调用,可以利用该过滤器进行身份验证、、在集群中选择请求的微服务,记录调试信息等。
route :在路由请求时候被调用,用于构建发送给微服务的请求,并使用Apache HttpClient或Netflix Ribbon请求微服务。
post:在routing和error过滤器之后被调用,可用来为响应添加标准的HTTP header、收集统计信息和指标、将响应从微服务发送给客户端等。
error:处理请求时发生错误时被调用
filterOrder:通过int值来定义过滤器的执行顺序,数值越小优先级越高
shouldFilter:返回一个boolean类型来判断该过滤器是否要执行。可以通过此方法来指定过滤器的有效范围
run:过滤器的具体逻辑。在该函数中,可以实现自定义的过滤逻辑,来确定是否要拦截当前的请求,不对其进行后续的路由,或是在请求路由返回结果之后,对处理结果做一些加工等。
Zuul 请求生命周期
Zuul默认定义四个不同的过滤器类型,它们覆盖一个外部HTTP请求到达API网关,直到返回请求结果的全部生命周期.
下图来自Zuul的官方WIKI中关于请求生命周期的图解,描述一个HTTP请求到达API网关之后,如何在各个不同类型的过滤器之间流转的详细过程。
当外部HTTP请求到达API网关服务的时候,首先会进入第一个阶段pre,会被pre类型的过滤器进行处理,该类型的过滤器主要目的是在进行请求路由之前做一些前置加工,比如请求的校验等
在完成pre类型的过滤器处理之后,请求进入第二个阶段routing,就是之前说的路由请求转发阶段,请求将会被routing类型过滤器处理,具体处理内容就是将外部请求转发到具体服务实例上去的过程
当服务实例将请求结果都返回之后,routing阶段完成,请求进入第三个阶段post,此时请求将会被post类型的过滤器进行处理,这些过滤器在处理的时候不仅可以获取到请求信息,还能获取到服务实例的返回信息,所以在post类型的过滤器中,可以对处理结果进行一些加工或转换等内容
还有一个特殊的阶段error,该阶段只有在上述三个阶段中发生异常的时候才会触发,但是它的最后流向还是post类型的过滤器,因为它需要通过post过滤器将最终结果返回给请求客户端
新建模块
新建个module:gateway-zuul-filter
pom依赖
<!-- eureka client 依赖 . Eureka不是必须的 ,在没有注册中心的情况下,也可以使用zuul --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> <!-- zuul 依赖 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-zuul</artifactId> </dependency>
application.yml配置文件
server:
port: 4536
spring:
application:
name: gateway-zuul-filter
eureka:
client:
service-url:
defaultZone: http://Jim:land123@localhost:8761/eureka
instance:
instance-id: ${spring.application.name}:${spring.application.instance_id:${server.port}}
#actuator 启用所有的监控端点 “*”号代表启用所有的监控端点,可以单独启用,例如,health,info,metrics
# spring boot 升为 2.0 后,为了安全,默认 Actuator 只暴露了2个端点,heath 和 info
management:
endpoints:
web:
exposure:
include: "*"
endpoint:
health:
show-details: ALWAYS
zuul:
routes:
provider-user: /userprovider/**
logging:
level:
com.netflix: DEBUG # 将 com.netflix包的日志级别设置为debug,将打印zuul的转发细节
自定义zuul过滤器
package com.smart.filter; import com.netflix.zuul.ZuulFilter; import com.netflix.zuul.context.RequestContext; import com.netflix.zuul.exception.ZuulException; import javax.servlet.http.HttpServletRequest; public class PreRequestZuulFilter extends ZuulFilter { @Override public String filterType() { return "pre"; } @Override public int filterOrder() { return 0; } @Override public boolean shouldFilter() { return true; } @Override public Object run() throws ZuulException { HttpServletRequest request = RequestContext.getCurrentContext().getRequest(); System.out.println("pre filter 的请求路径:"+request.getRequestURI()); return null; } }
自定义的zuul过滤器,需要继承 ZuulFilter,重写如上方法
filterType: 过滤器的类型,取值如下 pre route post error . 可以从源码的注释中看到
filterOrder:过滤器的执行顺序,不同的过滤器可以返回相同的数字
shouldFilter:表示该过滤器是否要执行,true执行,false不执行
run:过滤器的具体逻辑
初始化zuul过滤器
package com.smart; import com.smart.filter.PreRequestZuulFilter; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.zuul.EnableZuulProxy; import org.springframework.context.annotation.Bean; @SpringBootApplication @EnableZuulProxy public class GatewayZuulFilterApplication { public static void main(String[] args) { SpringApplication.run(GatewayZuulFilterApplication.class, args); } @Bean public PreRequestZuulFilter preRequestZuulFilter(){ return new PreRequestZuulFilter(); } }
package com.smart; import com.smart.filter.PreRequestZuulFilter; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.zuul.EnableZuulProxy; import org.springframework.context.annotation.Bean; @SpringBootApplication @EnableZuulProxy public class GatewayZuulFilterApplication { public static void main(String[] args) { SpringApplication.run(GatewayZuulFilterApplication.class, args); } @Bean public PreRequestZuulFilter preRequestZuulFilter(){ return new PreRequestZuulFilter(); } }
Step4 测试
启动microservice-discovery-eureka
启动micorservice-provider-user
启动microservice-gateway-zuul-filter
访问 http://localhost:4536/userprovider/user/2
禁用zuul过滤器
spring cloud 默认为zuul编写并启用了一些过滤器 ,禁用某个或某些过滤器,只需要 设置即可
zuul.<SimpleClassName>.<filterType>.disable=true
比如上面自定义的zuul filter, 我们过想禁用的话,两种方式
- 第一种方式:重写shouldFilter逻辑,返回false
- 第二种方式:application.yml中设置disable属性为true ,如下

package com.artisan.apigateway.filter; import com.netflix.zuul.ZuulFilter; import com.netflix.zuul.context.RequestContext; import org.springframework.http.HttpStatus; import org.springframework.stereotype.Component; import org.springframework.util.StringUtils; import javax.servlet.http.HttpServletRequest; import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.PRE_DECORATION_FILTER_ORDER; import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.PRE_TYPE; @Component public class TokenFilter extends ZuulFilter { @Override public String filterType() { return PRE_TYPE; } @Override public int filterOrder() { return PRE_DECORATION_FILTER_ORDER - 1; } @Override public boolean shouldFilter() { return true; } @Override public Object run() { RequestContext requestContext = RequestContext.getCurrentContext(); HttpServletRequest request = requestContext.getRequest(); //这里从url参数里获取, 也可以从cookie, header里获取 String token = request.getParameter("token"); if (StringUtils.isEmpty(token)) { requestContext.setSendZuulResponse(false); requestContext.setResponseStatusCode(HttpStatus.UNAUTHORIZED.value()); } return null; } }
浙公网安备 33010602011771号