天天看点

API网关服务-Spring Cloud Zuul

Spring Cloud Zuul基于Netflix Zuul实现的API网关组件,解决如下问题:

1 路由规则与服务实例的维护问题

与Eureka整合,将自身注册为Eureka服务治理下的应用,同时获取所有其他微服务的实例信息。
           

2 签名校验与登录校验的问题

Zuul提供了一套过滤器机制解决。
           

引入如下依赖

<dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
           

启动类添加如下注解

@EnableZuulProxy
           

请求路由

传统路由方式

面向服务路由

与Eureka整合,引入Eureka Client依赖

zuul.routes.service-a.path=/service/**
zuul.routes..service-a.service-id=boot-1
           

Zuul核心功能:请求过滤

只需继承ZuulFilter类,并重写其方法即可

filterType函数,决定过滤器在请求的执行周期,如 'pre'
filterOrder函数,决定过滤器的执行顺序,
shouldFilter函数,决定过滤器是否执行,返回ture
run函数,过滤器的具体逻辑
           

路由详解

传统路由

单实例配置
zuul.routes.<routes>.path=/service/**
zuul.routes.<routes>.url=http://127.0.0.1/service/**
多实例配置
zuul.routes.<routes>.path=/service/**
zuul.routes.<routes>.service-id=service
           

面向服务路由

zuul与Eureka整合,zuul也作为服务注册到Eureka注册中心,从注册中心获得了所有的服务清单
           

注意:默认情况下Zuul会对所有服务路由,默认规则的path就是service-id的服务名作为路由请求前缀

zuul.ignored-services= 配置可以设置不进行路由
           

自定义路由映射规则

PatternServiceRouteMapper
           

路径匹配

在Zuul中,路由匹配的路径表达式采用Ant风格定义,支持三种通配符

?匹配任意单个字符
* 匹配任意多个字符
** 匹配任意多个字符,支持层级目录
           

假设原来有一个服务user-service,路由为user-service,现在拆分出来一个user-service-ext,希望其路径为user-service/ext/,

根据路由匹配算法,匹配请求路径是采用线性遍历方式,匹配到符合条件的第一个路径时结束匹配并返回,     所以当存在多个时,匹配路径完全取决于路由规则的保存,路由规则由LinkedHashMap保存的,由于用   properties文件无法保证有序,所以需要用YAML文件。
           

忽略表达式

zuul.ignored-services=/url 表示不会路由此url
           

路由前缀

zuul.prefix= 表示会对路由增加默认前缀
           

本地跳转

zuul.routes.<service>.url=forward:/url 
           

cookie与头信息

默认情况下,Zuul在路由时会过滤HTTP请求的敏感信息,防止会传递到下游。此时会造成无法认证和鉴权
           

解决方案:

zuul.sensitive-headers= 不推荐,破坏了默认设置的用意
通过指定路由的参数来配置
zuul.routes.service.custom-sensitive-headers=true  对指定路由开启自定义敏感头
zuul.routes..service.sensitive-headers= 将指定路由的敏感头设置为空
           

重定向问题

解决了cookie问题后,发现了一个新问题。虽然可以通过网关登录页面发起登录请求,但是登陆成功后,跳转的页面确实具体的web实例的地址,而不是网关的地址。
           

解决方案

zuul.add-host-header=true
           

Hystrix和Ribbon支持

spring-cloud-starter-netflix-zuul依赖本身就包含了hystrix和ribbon支持,zuul具备线程隔离和保护器的功能,以及对服务调用的客户端负载均衡功能。
zuul.retryable=false 全局关闭重试
zuul.routes.service.retryable=false 指定路由关闭重试
           

过滤器详解

路由 主要通过pre类型的过滤器完成
四个基本特征:过滤类型,执行顺序,执行条件,具体操作
过滤类型 filterType:pre 请求被路由前
routing 路由请求时 
post 在routing和error之后被调用
 error 处理请求发生错误时
 执行顺序  filterOrder,数值越小,优先级越高
 执行条件 shouldFilter返回一个boolean类型表示是否执行,通过此方式指定过滤器的有效范围
 具体操作 run 过滤器的具体逻辑
过滤
           

请求生命周期

核心过滤器

pre过滤器

ServletDetectionFilter -3,最先被执行的过滤器,总会执行,主要用来检查当前请求是通过Spring的DispatcherServlet还是Zuul的ZuulServlet执行的,一般都是DispatcherServlet执行的
Servlet30WrapperFilter -2,会对所有请求生效,主要是把HttpServletRequest包装成HttpServletRequestWrapper对象
FormBodyWrapperFilter -1,仅对两类请求生效,一是Content-Type是application/x-www-form-urlencoded的请求,二是multipart/form-data并且是由DispatcherServlet处理的请求(用到了ServletDetectionFilter的处理结果)。主要目的是将符合要求的请求体包装成FormBodyRequestWrapper对象
DebugFilter 1,该过滤器具体操作的内容是将当前请求上下文的debugRouting和debugRequest设置为ture
PreDecorationFilter 5,判断当前请求的上下文是否存在forward.to和requestId参数。
           

routing过滤器

RibbonRoutingFilter 10,只对请求上下文中存在serviceId参数的请求处理,该请求的逻辑就是面向服务路由的核心,通过使用Hystrix和Ribbon来向服务实例发起请求,并将请求实例的结果返回
SimpleHostRoutingFilter 100,只对请求上下文中存在routeHost参数的请求处理,此类请求是通过httpclient包实现的,故而没有线程隔离和断路器的保护
SendForwardFilter 500,只对请求上下文中存在forward.to参数的请求处理,用来处理路由规则中的forward本地跳转配置
           

post过滤器

SendResponseFilter 1000检查请求上下文中是否包含请求响应相关的头信息,响应数据流或者响应体,包含其中一个才会处理,逻辑是利用请求上下文的逻辑信息组织需要发挥客户端的相应内容。
           

error过滤器

SendErrorFilter 0 只对请求上下文中存在error.status_code参数并且还没有被该过滤器执行过的时候处理处理。逻辑为利用请求上下文的错误信息来组成一个forward到API网关/error的错误信息
           

异常处理

Zuul过滤器的核心处理器-FilterProcessor

processZuulFilter函数 过滤器调度的核心函数,可扩展
           

禁用过滤器

zuul.<ClassName>.<filterType>.disable=true
           

动态加载

动态路由

结合Spring Cloud Config即可实现
           

动态过滤器

结合Groovy语言的动态性实现
           

继续阅读