Zuul的常用注解及配置
Zuul 微服务网关
作用:
Zuul的核心其实就是一系列过滤器
-身份认证与安全
-审查与监控
-动态路由
-压力测试
-负载分配
-静态响应处理
-多区域弹性
加入Zuul后的软件架构:
Zuul的spring依赖自带了springweb依赖,因此建项目时只要导入Zuul依赖即可
引入eureka客户端依赖,以拉取客户端列表
在主类上加入注解:
@EnableZuulProxy //开启Zuul的网关功能
配置文件:
server:
port: 10010
spring:
application:
name: zuul
eureka:
client:
service-url:
defaultZone: http://127.0.0.1:10086/eureka
zuul:
routes:
user-uservice: /user-service/** #这是默认的路由条目,只要zuul连上eureka就会获取eureka上的服务列表,并且根据这个服务列表提供所有服务的自动配置,而且此默认的路由一直都存在,即:不管你写不写,都有这条
user-service: /user/** #访问地址为127.0.0.1:10010/user/user/16
ignored-services: #这里是不路由的服务,书写方式是集合的方式
- consumer-service
去除路由前缀:
server:
port: 10010
spring:
application:
name: zuul
eureka:
client:
service-url:
defaultZone: http://127.0.0.1:10086/eureka
zuul:
routes:
user-service:
path: /user/**
serviceId: user-service
strip-prefix: false //去除路由前缀,默认为true,改为false即使user-serivce这条路由的/user路径不做去除,发送给真实路径,则访问地址为127.0.0.1:10010/user/16,因为匹配路径的/user/会发送给真实路径,但使用此功能无法简化路由条目配置
ignored-services: #这里是不路由的服务,书写方式是集合的方式
- consumer-service
过滤器:
ZuulFilter是过滤器的顶级父类。在这里我们看一下其中定义的4个最重要的方法:
public abstract ZuulFilter implements IZuulFilter{ abstract public String filterType(); abstract public int filterOrder(); boolean shouldFilter();// 来自IZuulFilter Object run() throws ZuulException;// IZuulFilter }
-
shouldFilter
:返回一个Boolean
值,判断该过滤器是否需要执行。返回true执行,返回false不执行。 -
run
:过滤器的具体业务逻辑。 -
filterType
:返回字符串,代表过滤器的类型。包含以下4种:-
pre
-
routing
:在路由请求时调用 -
post
:在routing和errror过滤器之后调用 -
error
:处理请求时发生错误调用
-
-
filterOrder
:通过返回的int值来定义过滤器的执行顺序,数字越小优先级越高。
过滤器执行的生命周期:
-
-
请求到达首先会经过pre类型过滤器,而后到达routing类型,进行路由,请求就到达真正的服务提供者,执行请求,返回结果后,会到达post过滤器。而后返回响应。
-
-
异常流程:
-
整个过程中,pre或者routing过滤器出现异常,都会直接进入error过滤器,再error处理完毕后,会将请求交给POST过滤器,最后返回给用户。
-
如果是error过滤器自己出现异常,最终也会进入POST过滤器,而后返回。
-
-
Zuul所有内置过滤器列表:
使用场景:
-
-
异常处理:一般会在error类型和post类型过滤器中结合来处理。
-
自定义过滤器:
模拟一个登录的校验。
基本逻辑:如果请求中有access-token参数,则认为请求有效,放行。
@Component public class LoginFilter extends ZuulFilter{ @Override public String filterType() { // 登录校验,肯定是在前置拦截 return FilterConstants.PRE_TYPE; } @Override public int filterOrder() { // 该常量值为5 ,减1后为4 return FilterConstants.PRE_DECORATION_FILTER_ORDER - 1; } @Override public boolean shouldFilter() { // 返回true,代表过滤器生效。 return true; } @Override public Object run() throws ZuulException { // 登录校验逻辑。 // 1)获取Zuul提供的请求上下文对象 RequestContext ctx = RequestContext.getCurrentContext();//RequestContext是一个Request域,此域的作用范围是从请求到达zuul一直到路由结束返回到客户端,整个完整流程都会存在 // 2) 从上下文中获取request对象 HttpServletRequest req = ctx.getRequest(); // 3) 从请求中获取token String token = req.getParameter("access-token"); // 4) 判断 if(StringUtils.isBlank(token)){ //StringUtils,需引apache的commons-lang3包的依赖 使用此方式可以避免内存溢出 // 没有token,登录校验失败,拦截 ctx.setSendZuulResponse(false);//true则放行,false则拦截 // 返回403状态码。也可以考虑重定向到登录页。 ctx.setResponseStatusCode(HttpStatus.Forbidden.value()); } // 校验通过,可以考虑把用户信息放入上下文,继续向后执行 return null;//默认为空即为放行 } }
此时使用http://127.0.0.1:10010/user/16 网页会跳转403
使用http://127.0.0.1:10010/user/16?access-token=1212121 即可正常访问,此案例只是验证access-token是否存在,不验证access-token的正确性
Zuul的负载均衡ribbon和熔断hystrix
在zuul的配置文件中配置
server:
port: 10010
spring:
application:
name: zuul
eureka:
client:
service-url:
defaultZone: http://127.0.0.1:10086/eureka
zuul:
routes:
user-service:
path: /user/**
serviceId: user-service
strip-prefix: false
ignored-services:
- consumer-service
zuul: retryable: true ribbon: ConnectTimeout: 250 # 连接超时时间(ms) ReadTimeout: 2000 # 通信超时时间(ms) OkToRetryOnAllOperations: true # 是否对所有操作重试 MaxAutoRetriesNextServer: 2 # 同一服务不同实例的重试次数 MaxAutoRetries: 1 # 同一实例的重试次数 hystrix: command: default: execution: isolation: thread: timeoutInMillisecond: 6000 # 熔断超时时长:6000ms
由于ribbon一次访问失败后会自动重试一次,因此 ( ConnectTimeout + ReadTimeout ) × 2 < timeoutInMillisecond
即:
timeoutInMillisecond的真实值是: ( ConnectTimeout + ReadTimeout ) × 2
公式:
timeoutInMillisecond = ( ribbon ConnectTimeout + ribbon ReadTimeout ) * (maxAutoRetries + 1) * ( maxAutoRetriesNextServer + 1 );