SpringBoot + Spring Cloud +Vue 管理系统搭建(十四、服务网关Zuul)
前面我们已经通过Ribbon或者Feign实现了负载均衡,那我们的各种微服务如何给外界调用呢?
就是通过我们的网关
使用网关的优点:
易于监控,可在网关上收集监控数据并将其推送到外部系统进行分析
易于认证,在网关上进行认证,然后转发到请求的微服务
客户端只跟服务网关打交道,减少客户端与各个微服务的交互次数
多渠道支持,可以根据不同的客户端(Web、移动端)提供不同的API
Spring Cloud Netflix 封装了Zuul组件,作为一个API网关,负责提供负载均衡、反向代理和权限认证。
Zuul工作机制
zuul的核心是一系列的filters,作用类似Servlet中的Filter,这些filter在路由的特定时期参与一些过滤处理,比如实现鉴权、流量转发、请求统计等功能。
下面是机制图
生命周期
Filter生命周期有4个阶段分别是PRE、ROUTING、POST、ERROR
下面是生命周期图
(1) PRE:这种过滤器在请求被路由之前调用。我们可利用这种过滤器实现身份验证、在集群中选择请求的微服务、记录调试信息等。
(2) ROUTING:这种过滤器将请求路由到微服务。这种过滤器用于构建发送给微服务的请求,并使用Apache HttpClient或Netfilx Ribbon请求微服务。
(3) POST:这种过滤器在路由到微服务以后执行。这种过滤器可用来为响应添加标准的HTTP Header、收集统计信息和指标、将响应从微服务发送给客户端等。
(4) ERROR:在其他阶段发生错误时执行该过滤器。
除了默认的过滤器类型,Zuul还允许我们创建自定义的过滤器类型。
Zuul中默认实现的Filter
类型 顺序 过滤器 功能
pre -3 ServletDetectionFilter 标记处理Servlet的类型
pre -2 Servlet30WrapperFilter 包装HttpServletRequest请求
pre -1 FormBodyWrapperFilter 包装请求体
route 1 DebugFilter 标记调试标志
route 5 PreDecorationFilter 处理请求上下文供后续使用
route 10 RibbonRoutingFilter serviceId请求转发
route 100 SimpleHostRoutingFilter url请求转发
route 500 SendForwardFilter forward请求转发
post 0 SendErrorFilter 处理有错误的请求响应
post 1000 SendResponseFilter 处理正常的请求响应
禁用Filter
我们可以在application.yml中配置需要禁用的filter
格式 zull.<ClassName>.<filterType>.disable=true
例如禁用org.springframework.cloud.netflix.zuul.filters.post.SendResponseFilter
zuul:
SendResponseFilter:
post:
disable: true
自定义Filter
public class MyFilter extends ZuulFilter { final static Logger logger = LoggerFactory.getLogger(FirstFilter.class); // 表示是否需要执行改filter true表示执行 false表示不执行 public boolean shouldFilter() { return true; } public Object run() { 20000 //filter需要执行的具体操作 return null; //直接返回null即可 } @Override public String filterType() { // 定义filter类型 //pre:可以在请求被路由之前调用 //route:在路由请求时候被调用 //post:在route和error过滤器之后被调用 //error:处理请求时发生错误时被调用 return "pre"; } @Override public int filterOrder() { //定义filter的顺序 优先级为0,数字越大,优先级越低 return 0; } }
下面我们写一个案例
新建一个mango-zuul作为服务网关
添加pom依赖
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.0.4.RELEASE</version> <relativePath /> <!-- lookup parent from repository --> </parent> <groupId>com.louis</groupId> <artifactId>mango-zuul</artifactId> <version>${project.version}</version> <packaging>jar</packaging> <name>mango-zuul</name> <description>mango-zuul</description> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <project.version>1.0.0</project.version> <java.version>1.8</java.version> <spring-cloud.version>Finchley.RELEASE</spring-cloud.version> </properties> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-zuul</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-consul-discovery</artifactId> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
启动类
启动类添加@EnableZuulProxy注解开启服务网关支持
@EnableZuulProxy @SpringBootApplication public class MangoZuulApplication { public static void main(String[] args) { SpringApplication.run(MangoZuulApplication.class, args); } }
配置文件
这里配置在访问localhost:8010/feigin/call和ribbon/call时调用消费者对应的接口
server: port: 8010 spring: application: name: mango-zuul cloud: consul: host: localhost port: 8500 discovery: serviceName: ${spring.application.name} # 注册到consul的服务名称 zuul: routes: ribbon: path: /ribbon/** serviceId: mango-consumer # 转发到消费者 /ribbon/ feign: path: /feign/** serviceId: mango-consumer # 转发到消费者 /feign/
到此我们配置完成,配置完依次启动注册中心、监控(monitor)、服务提供者(product)、服务消费者(consumer)、服务网关(zuul)
然后访问http://localhost:8010/ribbon/call、http://localhost:8010/feign/call这俩地址
我们可以看到zuul已经成功转发请求,并成功调用后端微服务。
配置接口前缀
如果想给每一个服务的API接口加上一个前缀,可以使用zuul.prefix进行配置。
例如:http://localhost:8010/v1/feign/call
zuul: prefix: /v1 #配置接口前缀 routes: ribbon: path: /ribbon/** serviceId: mango-consumer # 转发到消费者 /ribbon/ feign: path: /feign/** serviceId: mango-consumer # 转发到消费者 /feign/
默认路由
上面我们是通过添加路由配置进行请求转发,但是如果微服务非常多的话,配置起来比较麻烦。
spring cloud zuul已经帮我们做了默认配置,默认情况下,Zuul会代理所有注册到注册中心的微服务,并且Zuul的默认路由规则
是:http://ZUUL_HOST:ZUUL_PORT/微服务在注册中心的serviceId/** 会被转发到serviceId对应的微服务。
遵循这个规则我们就不需要配置路由转发了
例如:http://localhost:8010/mango-consumer/feign/call
就可以直接访问到mango-consumer中的方法
路由熔断
Zuul作为Netflix组件,可以与Ribbon、Eureka、Hystrix等组件结合,实现负载均衡、熔断器的功能。
默认情况下Zuul与Ribbon相结合,实现了负载均衡。实现熔断器功能需要实现FallbackProvider接口。实现该接口有两个方法:
1、getRoute() 用于指定熔断器功能应用于哪些路由服务
2、fallbackResponse() 为进熔断器功能时执行的逻辑
创建FallbackProvider类
@Component public class MyFallbackProvider implements FallbackProvider { @Override public String getRoute() { return "mango-consumer"; } @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("Sorry, the service is unavailable now.".getBytes()); } @Override public HttpHeaders getHeaders() { HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); return headers; } }; } }
这里getRoute()方法返回mango-consumer,只针对consumer服务进行熔断。
如果需要所有的路由服务都增加熔断,需要在getRoute() 方法返回“*”匹配符
getBody()方法返回给熔断时的反馈信息
到此,我们依次启动注册中心、监控(monitor)、服务提供者(product)、服务消费者(consumer)、服务网关(zuul)
正常访问没有问题
当我们停掉consumer再访问,可以看到我们的熔断已经起作用了
自定义Filter
创建一个MyFilter,继承ZuulFilter类,覆写run()方法逻辑,在转发请求前进行token认证,如果没有token,返回“there is norequest token”提示
@Component public class MyFilter extends ZuulFilter { private static Logger log=LoggerFactory.getLogger(MyFilter.class); @Override public String filterType() { return "pre"; // 定义filter的类型,有pre、route、post、error四种 } @Override public int filterOrder() { return 0; // 定义filter的顺序,数字越小表示顺序越高,越先执行 } @Override public boolean shouldFilter() { return true; // 表示是否需要执行该filter,true表示执行,false表示不执行 } @Override public Object run() throws ZuulException { // filter需要执行的具体操作 RequestContext ctx = RequestContext.getCurrentContext(); HttpServletRequest request = ctx.getRequest(); String token = request.getParameter("token"); System.out.println(token); if(token==null){ log.warn("there is no request token"); ctx.setSendZuulResponse(false); ctx.setResponseStatusCode(401); try { ctx.getResponse().getWriter().write("there is no request token"); } catch (IOException e) { e.printStackTrace(); } return null; } log.info("ok"); return null; } }
这样zuul就会自动加载Filter执行过滤了。重启我们的Zuul项目
访问:http://localhost:8010/mango-consumer/feign/call
可以看到已经返回我们自定义Filter的提示
下面我们加上token访问http://localhost:8010/mango-consumer/feign/call?token=1111
可以看到访问成功了
Zuul作为API网关服务,不同的客户端使用不同的负载将请求统一分发到后端的Zuul,
再由Zuul转发到后端服务。为了保证Zuul的可用性,前端可以同时开启多个Zuul实例进行负载均衡,
另外,在zuul的前端还可以使用Nginx或者F5再次进行负载转发,从而保证Zuul的高可用性。
好啦,Zuul我们就学到这里拉,看完记得点赞哦!!!
- Spring Boot + Spring Cloud 实现权限管理系统 后端篇(二十一):服务网关(Zuul)
- Spring Boot + Spring Cloud 构建微服务系统(七):API服务网关(Zuul)
- SpringCloud Finchley 实战入门(基于springBoot 2.0.3)【九 zuul 微服务网关配置】
- Spring Boot 和 Spring Cloud 实战 - 从无到有搭建信息管理系统(系统总体架构) -- TerryHe 博客园
- 基于Spring Boot、Spring Cloud & Alibaba、OAuth2的分布式微服务架构权限管理系统
- springcloud组件zuul搭建网关服务
- Spring Boot + Spring Cloud 实现权限管理系统 后端篇(十五):系统服务监控
- SpringBoot+Vue+ElementUI实现含国际化的前后端不分离的传统简易管理系统搭建(一)
- Spring Boot + Spring Cloud 实现权限管理系统 后端篇(二十):服务熔断(Hystrix、Turbine)
- SpringCloud-搭建Zuul网关服务(七)
- Spring Boot + Spring Cloud 实现权限管理系统 后端篇(十八):服务注册和发现(Consul)
- sringcloud2.0学习-16- springcloud微服务网关+Zuul网关搭建
- Spring Boot + Spring Cloud 实现权限管理系统 后端篇(十九):服务消费(Ribbon、Feign)
- 利用SpringCloud搭建微服务4——服务调用组件Fegin的使用,引入API网关治理组件Zuul
- 基于SpringCloud+vue(ElementUI)+mySQL前后端分离设计之--搭建权限管理系统
- SpringCloud 微服务 (十四) 服务网关 Zuul 过滤器(Pre&Post)
- Spring Boot + Spring Cloud 实现权限管理系统 后端篇(十):接口服务整理
- Spring Boot + Spring Cloud 实现权限管理系统 后端篇(十四):项目打包部署
- 新书上线:《Spring Boot+Spring Cloud+Vue+Element项目实战:手把手教你开发权限管理系统》,欢迎大家买回去垫椅子垫桌脚
- springcloud之服务网关Netflix Zuul与分布式配置Spring Cloud Config