SpringCloud(Hoxton.SR3)基础篇:第八章、SpringCloud之Zuul网关原理及其配置
简介:
Zuul是spring cloud中的微服务网关。网关: 是一个网络整体系统中的前置门户入口。请求首先通过网关,进行路径的路由,定位到具体的服务节点上。
Zuul是一个微服务网关,首先是一个微服务。也是会在Eureka注册中心中进行服务的注册和发现。也是一个网关,请求应该通过Zuul来进行路由。
Zuul网关不是必要的。是推荐使用的。
使用Zuul,一般在微服务数量较多(多于10个)的时候推荐使用,对服务的管理有严格要求的时候推荐使用,当微服务权限要求严格的时候推荐使用。
一、Zuul网关的作用
Zuul可以通过加载动态过滤机制,从而实现以下各项功能:
1.验证与安全保障: 识别面向各类资源的验证要求并拒绝那些与要求不符的请求。
2.审查与监控: 在边缘位置追踪有意义数据及统计结果,从而为我们带来准确的生产状态结论。
3.动态路由: 以动态方式根据需要将请求路由至不同后端集群处。
4.压力测试: 逐渐增加指向集群的负载流量,从而计算性能水平。
5.负载分配: 为每一种负载类型分配对应容量,并弃用超出限定值的请求。
6.静态响应处理: 在边缘位置直接建立部分响应,从而避免其流入内部集群。
7.多区域弹性: 跨越AWS区域进行请求路由,旨在实现ELB使用多样化并保证边缘位置与使用者尽可能接近。
二、Zuul网关的应用
1、网关访问方式
通过zuul访问服务的,URL地址默认格式为:http://zuulHostIp:port/要访问的服务名称/服务中的URL
服务名称:properties配置文件中的spring.application.name。
服务的URL:就是对应的服务对外提供的URL路径监听。
2、网关依赖注入
<!-- zuul相关引用 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-zuul</artifactId> </dependency> <!-- eureka客户端端依赖jar包 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency>
3、网关启动器
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.zuul.EnableZuulProxy; /** * @EnableZuulProxy - 开启Zuul网关。 * 当前应用是一个Zuul微服务网关。会在Eureka注册中心中注册当前服务。并发现其他的服务。 * Zuul需要的必要依赖是spring-cloud-starter-netflix-zuul。 */ @SpringBootApplication //zuul代理注解 @EnableZuulProxy public class ZuulApplication { public static void main(String[] args) { SpringApplication.run(ZuulApplication.class, args); } }
4、网关全局变量配置
4.1 application.yml配置
spring: application: name: springcloud-gateway-zuul server: port: 8040 #eureka客户端连接配置 eureka: client: service-url: #注册中心地址 defaultZone: http://user:password123@localhost:8761/eureka/ instance: #将ip注册到eureka上 prefer-ip-address: true
4.2 URL路径匹配
#zuul配置 #1.zuul默认从eureka读取全部注册微服务services并进行代理访问,默认示例:http://localhost:8040/provider-user/simple/3 zuul: #zuul代理路由配置 routes: #主键标志用来保持唯一,可以改成abc user: #zuul代理服务路径 path: /user-url/** url: http://localhost:7900/
4.3 服务名称匹配
#zuul配置 #1.zuul默认从eureka读取全部注册微服务services并进行代理访问,默认示例:http://localhost:8040/provider-user/simple/3 zuul: #zuul代理路由配置 routes: #主键标志用来保持唯一,可以改成abc user: #zuul代理服务路径 # 一、/* 只能访问一层路径 比如 user-path/simple # 二、/** 可以访问子路径 比如 user-path/simple/1 path: /user-path/** #eureka注册服务id service-id: provider-user
4.4 路由排除配置
#zuul配置 #1.zuul默认从eureka读取全部注册微服务services并进行代理访问,默认示例:http://localhost:8040/provider-user/simple/3 zuul: #zuul忽略代理的,表示禁用默认路由,只认我们自己配置的路由. ignoredServices: '*' #zuul代理路由配置 routes: provider-user: /user/**
4.5 路由前缀配置
#zuul配置 #1.zuul默认从eureka读取全部注册微服务services并进行代理访问,默认示例:http://localhost:8040/provider-user/simple/3 zuul: #前缀,当请求匹配前缀时会进行代理 prefix: /simple #代理前缀默认会从请求路径中移除,通过该设置关闭移除功能 strip-prefix: false logging: level: com.netflix: DEBUG
例:
当 strip-prefix=true 的时 (会移除)
(http://127.0.0.1:8040/api/provider-user/simple/3 -> http://192.168.1.100:7900/simple/3)
当 strip-prefix=false的时(不会移除)
(http://127.0.0.1:8040/api/provider-user/simple/3 -> http://192.168.1.100:7900/api/simple/3)
postman测试结果(通过网关请求服务提供者):
三、Zuul网关过滤器
1)过滤器实现方式
Zuul中提供了过滤器定义,可以用来过滤代理请求,提供额外功能逻辑。如:权限验证,日志记录等。
Zuul提供的过滤器是一个父类。父类是ZuulFilter。通过父类中定义的抽象方法filterType,来决定当前的Filter种类是什么。有前置过滤、路由后过滤、后置过滤、异常过滤。
- 前置过滤(pre):前置过滤器,在请求被路由前执行,通常用于处理身份认证,日志记录等;
- 路由后过滤(route):在路由执行后,服务调用前被调用;
- 后置过滤(post): 在route或error执行后被调用,一般用于收集服务信息,统计服务性能指标等,也可以对response结果做特殊处理。
- 异常过滤(error):任意一个filter发生异常的时候执行或远程服务调用没有反馈的时候执行(超时),通常用于处理异常;
2)过滤器的生命周期
3)代码示例
import javax.servlet.http.HttpServletRequest; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.netflix.zuul.ZuulFilter; import com.netflix.zuul.context.RequestContext; import com.netflix.zuul.exception.ZuulException; public class PreZuulFilter extends ZuulFilter{ private static final Logger LOGGER = LoggerFactory.getLogger(PreZuulFilter.class); /** * 表示是否使用该过滤器 */ @Override public boolean shouldFilter() { return true; } /** * 具体的过滤执行逻辑 */ @Override public Object run() throws ZuulException { HttpServletRequest request = RequestContext.getCurrentContext().getRequest(); String host = request.getRemoteHost(); PreZuulFilter.LOGGER.info("请求的host:{}", host); return null; } /** * 过滤器类型 * */ @Override public String filterType() { // TODO Auto-generated method stub return "pre"; } /** * 过滤器执行顺序。返回值越小,执行顺序越优先。 */ @Override public int filterOrder() { // TODO Auto-generated method stub return 1; } }
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.zuul.EnableZuulProxy; import org.springframework.context.annotation.Bean; import com.qxj.cloud.filter.PreZuulFilter; @SpringBootApplication //zuul代理注解 @EnableZuulProxy public class ZuulApplication { public static void main(String[] args) { SpringApplication.run(ZuulApplication.class, args); } /** * 将过滤器交给Spring管理 * @return */ @Bean public PreZuulFilter preZuulFilter() { return new PreZuulFilter(); } }
四、Zuul的Fallback回退机制
默认情况下,经过Zuul的请求都会使用Hystrix进行包裹,所以Zuul本身就具有断路器的功能。
代码示例如下:
import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import org.springframework.cloud.netflix.zuul.filters.route.FallbackProvider; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.client.ClientHttpResponse; import org.springframework.stereotype.Component; /** * FallbackProvider实现类 */ @Component public class MyFallbackProvider implements FallbackProvider { /** * 表明是为哪个微服务提供回退,*表示为所有微服务提供回退 */ @Override public String getRoute() { return "provider-user"; } /** * fallback逻辑。 */ @Override public ClientHttpResponse fallbackResponse(String route, Throwable cause) { System.out.println("route:" + route); System.out.println("exception:" + cause.getMessage()); return new ClientHttpResponse() { @Override public HttpStatus getStatusCode() throws IOException { return HttpStatus.OK; } @Override public int getRawStatusCode() throws IOException { return 200; } @Override public String getStatusText() throws IOException { return "ok"; } @Override public void close() { } @Override public InputStream getBody() throws IOException { return new ByteArrayInputStream("oooops!error,i'm the fallback.".getBytes()); } @Override public HttpHeaders getHeaders() { HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); return headers; } }; } }
停止provider微服务。Postman执行测试结果