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本身就是个字符串而已,换成谷歌就好了