1. zuul 的简单集成
在 pom.xml 中添加 zuul 依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
2. 在 application.properties 中添加, 在启动类上添加 @EnableZuulProxy 注解
zuul.routes.cxytiandi.path=/cxytiandi/**
zuul.routes.cxytiandi.url=http://cxytiandi.com/
然后访问 http://ip-yuming:port/cxytiandi , 然后会直接跳转到 http://cxytiandi.com
3. 集成 eureka
在 pom.xml 中添加依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
在 application.properties 中添加
eureka.client.service-url.defaultZone=http://xiaohaibo:10010@localhost:8761/eureka/
然后就可以直接访问其他服务的api了, http://localhost:2103/fsh-house/house/hello, 访问规则: API网关地址 + 访问服务名称 + 接口 URI
4. zuul 的路由配置
默认的路由转发 API 网关地址 + 访问的服务名称 + 接口URI
http://localhost:2103/fsh-substitution/substitution/callHello
zuul.routes.fsh-substitution.path=/house-api/**
zuul.routes.fsh-substitution.url=fsh-substitution #可省略
配置过后, 就可以在浏览器中访问 http://localhost:2103/house-api/substitution/callHello
路由前缀, 有时候想在 API 前面配置一个统一的前缀
zuul.prefix=/rest
加过前缀后: http://localhost:2103/rest/house-api/substitution/callHello
配置本地跳转
zuul.routes.local-a.path=/a-api/**
zuul.routes.local-a.url=forward:/local
然后访问 http://localhost:2103/a-api/1 就等于访问 http://localhost:2103/local/1
5. zuul 的过滤器
zuul 中的过滤器和 javax.servlet.Filter 不一样, Filter 只有一种类型, 可以通过配置 urlPatterns 来拦截对应请求.
zuul 中的过滤器总共有 4 中类型.
① pre : 可以在请求被路由之前调用, 适用于身份验证场景, 认证通过后在继续执行.
② route : 在路由请求时被调用, 适用于灰度发布场景, 在将要路由的时候可以做一些自定义逻辑.
③ error : 处理请求发生错误的时候被调用, 在执行过程中发生错误的时候会进入 error 过滤器, 可以用来记录统一的错误信息.
④ post : 在 route 和 error 过滤器之后被调用, 这种过滤器将请求路由到达具体的服务之后执行,适用于需要添加响应头, 记录响应日志等场景.
6. 请求的生命周期
从上图看出, 请求发来先到 pre 过滤器, 再到 route 过滤器, 然后到 post 过滤器 这三个任何一个有异常都会进入 error 过滤器.
从 com.netflix.zuul.http.ZuulServlet.service(ServletRequest, ServletResponse) 源码可以看出来过滤器的执行顺序.
7. 使用过滤器
zuul 自定义过滤器是继承 ZuulFilter , 需要实现以下几个方法
shouldFilter: 是否执行该过滤器, true 是执行, false 是不执行.
filterType: 过滤器的类型, 可选值有 pre, route, post, error
filterOrder: 过滤器的执行顺序, 数值越小, 优先级越高.
run 执行自己的业务逻辑, 例如可以通过设置 ctx.setSendZuulResponse(false) 告诉 zuul 不需要将当前请求转发到后台服务了,通过设置 setResponseBody 返回数据给客户端.
过滤器定义完成后, 需要注册才能够生效.
8. 过滤器的禁用
可以使用 shouldFilter 中的 false
也可以在配置文件中配置
# zuul.过滤器的类名.过滤器的类型.disable=true
zuul.IpFilter.pre.disable=false
9. 过滤器中的数据传递
过滤器中的数据传递使用 RequestContext 的 set 方法.
10. 过滤器拦截请求
zuul 过滤器和 javax.servlet.Filter 不同的是, 第一个 Filter 执行之后, 如果不满足业务, 后面的 Filter 还是会执行的.
拦截和返回结果可以通过下面代码实现
RequestContext ctx = RequestContext.getCurrentContext();
ctx.setSendZuulResponse(false);
ctx.setResponseBody("返回信息");
return null;
可以给后面的 Filter 的 shouldFilter 方法传递一个参数, 来控制后面的 Filter 是否执行.
ctx.set("isSuccess", "false");
11. zuul 过滤器的异常处理
zuul 过滤器发生异常, 一般都是在 run 方法里, 没有捕获的, 都会最终到 error 过滤器中, 我们可以先定义一个 error 异常, 然后在 run 方法里处理一下异常
然后我们在定义一个统一异常处理 Controller 类
12. Zuul 容错
zuul 的主要功能是转发, 在转发的过程中无法保证被调用的服务是可用的, 这个时候就要有容错机制 和 回退机制.
容错机制简单说就是当某个服务不可用的时候, 能够切换到其他可用的服务上去, 也就是需要又重试机制.
zuul 重试机制依赖 spring-retry
<dependency>
<groupId>org.springframework.retry</groupId>
<artifactId>spring-retry</artifactId>
</dependency>
# 开启重试
zuul.retryable=true
# 请求链接超时时间
ribbon.ConnectTimeout=500
# 请求处理超时时间
ribbon.ReadTimeout=5000
# 对当前实例的重试次数
ribbon.MaxAutoRetries=1
# 切换实例的最大重试次数
ribbon.MaxAutoRetriesNextServer=3
# 对所有操作请求都进行重试
ribbon.OkToRetryOnAllOperations=true
ribbon 的默认默认规则是轮询, 可以同时启动 两个 fsh-house 服务, 然后停掉其中一个, 没有重试机制之前会报异常信息, 有重试机制后, 就会去循环请求接口, 调用正常的返回结果.
13. zuul 的回退
在 Spring Cloud 中 zuul 默认整合了 Hystrix, 当后端服务异常的时候可以为 zuul 添加回退功能.
实现 org.springframework.cloud.netflix.zuul.filters.route.FallbackProvider 接口
getRoute() 返回 * 标识对所有服务进行回退. 也可以返回具体的服务名称, 服务名称需要在 eureka 中注册.
14. zuul 高可用
zuul 高可用不能通过注册 eureka 实现, 而是通过 Nginx 或 HAProxy 等来实现.