springcloud应用之zuul
阅读提示
zuul是什么
zuul是netflix提供的一个有路由,过滤和容错回退功能的一个组件
路由功能负责将外部请求转发到具体的微服务实例上,是实现外部访问统一入口的基础 过滤器功能则负责对请求的处理过程进行干预,是实现请求校验、服务聚合等功能的基础.
Zuul和Eureka进行整合,将Zuul自身注册为Eureka服务治理下的应用,同时从Eureka中获得其他微服务的消息,
也即以后的访问微服务都是通过Zuul跳转后获得。
注意:Zuul服务最终还是会注册进Eureka
为什么需要zuul
我们之前都是直接访问user微服务,user微服务再去调用order,这样将所有微服务暴露出来是不安全的,并且也不便于统一管理,所以就有了zuul,他负责当好所有微服务的入口,所有请求经过zuul,再被zuul路由到各自的微服务
单体zuul搭建
先建一个eureka-client项目,不会建的建议看我之前的博客系列,我的cloud是一个专题系列,再eureka里说了如何建项目
启动类加上@EnableZuulProxy
pom文件
<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>
yml文件
# 服务名称 spring: application: name: zuul # 服务端口号 server: port: 8200 #Eureka 相关配置 eureka: instance: instance-id: zuul prefer-ip-address: true client: service-url: defaultZone: http://server7000:7000/eureka,http://server7001:7001/eureka,http://server7002:7002/eureka zuul: #prefix: /api #访问路径加上前缀 #strip-prefix: false #防止requestMapping上的api和prefix冲突 ignored-services: "*" #进制直接访问除了zuul的其他微服务客户端 routes: user: serviceId: user8100 # serviceId是user微服务的application name path: /user/** order: serviceId: order path: /order/**
这样就建好了,我们访问localhost:8200/user/testFeignAndHystrix 就可以了
routes可以不加,不过访问路径得改为localhost:8200/user8100/testFeignAndHystrix
负载均衡zuul搭建
如果zuul挂掉了整个集群就崩溃了,所以zuul也得做集群
再建两台zuul-server-8201,zuul-server-8202
修改好pom文件和启动类
zuul-8200
zuul-server-8201
zuul-server-8202
三者的yml文件如下:
zuul-8200
# 服务名称 spring: application: name: zuul # 服务端口号 server: port: 8200 #Eureka 相关配置 eureka: instance: instance-id: zuul prefer-ip-address: true client: service-url: defaultZone: http://server7000:7000/eureka,http://server7001:7001/eureka,http://server7002:7002/eureka zuul: #prefix: /api #访问路径加上前缀 #strip-prefix: false #防止requestMapping上的api和prefix冲突 ignored-services: "*" #进制直接访问除了zuul的其他微服务客户端 routes: zuul: #访问路径的一部分 serviceId: zuul-server #8201和8202的application name path: /**
zuul-server-8201
# 服务名称 spring: application: name: zuul-server # 服务端口号 server: port: 8201 #Eureka 相关配置 eureka: instance: instance-id: zuul-server-1 prefer-ip-address: true client: service-url: defaultZone: http://server7000:7000/eureka,http://server7001:7001/eureka,http://server7002:7002/eureka zuul: #prefix: /api #访问路径加上前缀 #strip-prefix: false #防止requestMapping上的api和prefix冲突 ignored-services: "*" #进制直接访问除了zuul的其他微服务客户端 routes: user: serviceId: user8100 # serviceId是user微服务的application name path: /user/** order: serviceId: order path: /order/**
zuul-server-8202
# 服务名称 spring: application: name: zuul-server # 服务端口号 server: port: 8202 #Eureka 相关配置 eureka: instance: instance-id: zuul-server-2 prefer-ip-address: true client: service-url: defaultZone: http://server7000:7000/eureka,http://server7001:7001/eureka,http://server7002:7002/eureka zuul: #prefix: /api #访问路径加上前缀 #strip-prefix: false #防止requestMapping上的api和prefix冲突 ignored-services: "*" #进制直接访问除了zuul的其他微服务客户端 routes: user: serviceId: user8100 # serviceId是user微服务的application name path: /user/** order: serviceId: order path: /order/**
zuul集群就搭建好了,访问http://localhost:8200/zuul/user/testFeignAndHystrix
至此我们的项目有点复杂了,得画张图理解一下
zuul过滤
过滤器(filter)是zuul的核心组件 zuul大部分功能都是通过过滤器来实现的。
zuul中定义了4种标准过滤器类型,这些过滤器类型对应于请求的典型生命周期。
PRE:这种过滤器在请求被路由之前调用。可利用这种过滤器实现身份验证、在 集群中选择请求的微服务、记录调试信息等。
ROUTING:这种过滤器将请求路由到微服务。这种过滤器用于构建发送给微服 务的请求,并使用 Apache HttpCIient或 Netfilx Ribbon请求微服务
POST:这种过滤器在路由到微服务以后执行。这种过滤器可用来为响应添加标准 的 HTTP Header、收集统计信息和指标、将响应从微服务发送给客户端等。
ERROR:在其他阶段发生错误时执行该过滤器。
如果要编写一个过滤器,则需继承ZuulFilter类 实现其中方法:
把下面类放到zuul8200里即可
@Component public class LogFilter extends ZuulFilter { @Override public String filterType() { return FilterConstants.PRE_TYPE; } @Override public int filterOrder() { return FilterConstants.PRE_DECORATION_FILTER_ORDER+1; } @Override public boolean shouldFilter() { return true; } @Override public Object run() throws ZuulException { RequestContext currentContext = RequestContext.getCurrentContext(); HttpServletRequest request = currentContext.getRequest(); String remoteAddr = request.getRemoteAddr(); String url = currentContext.get(FilterConstants.REQUEST_URI_KEY).toString(); System.out.println("访问者IP:"+remoteAddr+"访问地址:"+request.getRequestURI()+" 路由后地址"+url); return null; } }
容错
zuul8200加入
@Component class MyFallbackProvider implements FallbackProvider { @Override public String getRoute() { return "*"; //所有微服务,也可以指定 } //超时或者挂掉才fallbackResponse,微服务抛异常不会进,刚开始我在这卡住了 @Override public ClientHttpResponse fallbackResponse(String route, final Throwable cause) { if (cause instanceof HystrixTimeoutException) { return response(HttpStatus.GATEWAY_TIMEOUT); } else { return response(HttpStatus.INTERNAL_SERVER_ERROR); } } private ClientHttpResponse response(final HttpStatus status) { return new ClientHttpResponse() { @Override public HttpStatus getStatusCode() throws IOException { return status; } @Override public int getRawStatusCode() throws IOException { return status.value(); } @Override public String getStatusText() throws IOException { return status.getReasonPhrase(); } @Override public void close() { } @Override public InputStream getBody() throws IOException { return new ByteArrayInputStream("fallback".getBytes()); } @Override public HttpHeaders getHeaders() { HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); return headers; } }; } }
停掉user微服务访问http://localhost:8200/user/testFeignAndHystrix 发现返回fallback, 火狐浏览器返回json解析异常,因为fallback本身就是个字符串而已,换成谷歌就好了