SpringCloud学习之Zuul路由转发、拦截和熔断处理(七)

Spring Cloud Zuul

服务网关是微服务架构中一个不可或缺的部分。通过服务网关统一向外系统提供REST API的过程中,除了具备服务路由、均衡负载功能之外,它还具备了权限控制等功能。

Spring Cloud Netflix中的Zuul就担任了这样的一个角色,为微服务架构提供了前门保护的作用,同时将权限控制这些较重的非业务逻辑内容迁移到服务路由层面,使得服务集群主体能够具备更高的可复用性和可测试性。

在Spring Cloud体系中, Spring Cloud Zuul 封装了Zuul组件,作为一个API网关,负责提供负载均衡、反向代理和权限认证。

Zuul工作机制

过滤器机制

Zuul的核心是一系列的filters, 其作用类似Servlet框架的Filter,Zuul把客户端请求路由到业务处理逻辑的过程中,这些filter在路由的特定时期参与了一些过滤处理,比如实现鉴权、流量转发、请求统计等功能。Zuul的整个运行机制,可以用下图来描述。

过滤器的生命周期

Filter的生命周期有4个,分别是“PRE”、“ROUTING”、“POST”、“ERROR”,整个生命周期可以用下图来表示。

基于Zuul的这些过滤器,可以实现各种丰富的功能,而这些过滤器类型则对应于请求的典型生命周期。

PRE: 这种过滤器在请求被路由之前调用。我们可利用这种过滤器实现身份验证、在集群中选择请求的微服务、记录调试信息等。

ROUTING:这种过滤器将请求路由到微服务。这种过滤器用于构建发送给微服务的请求,并使用Apache HttpClient或Netfilx Ribbon请求微服务。

POST:这种过滤器在路由到微服务以后执行。这种过滤器可用来为响应添加标准的HTTP Header、收集统计信息和指标、将响应从微服务发送给客户端等。

ERROR:在其他阶段发生错误时执行该过滤器。

除了默认的过滤器类型,Zuul还允许我们创建自定义的过滤器类型。例如,我们可以定制一种STATIC类型的过滤器,直接在Zuul中生成响应,而不将请求转发到后端的微服务。

Zuul中默认实现的Filter

Zuul默认实现了很多Filter,这些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

处理正常的请求响应

我们先看看Zuul的工作原理,Zuul是主要起路由转发和路由拦截作用的,这里直接说Zuul和Feign集成的工作流程如下:

新建一个Consumer服务消费模块,他的pom.xml添加如下依赖:

看看他的主程序:

再看看application.yml里的配置文件:

1eureka: 2 client: 3 serviceUrl: 4 defaultZone: http://localhost:8761/eureka/ 5 instance: 6 prefer-ip-address: true 7server: 8 port: 8768 9spring: 10 application: 11 name: service-ribbon 12zuul: 13 routes: 14 #标识你服务的名字,这里可以自己定义,一般方便和规范来讲还是跟自己服务的名字一样 15 service-feign: 16 #服务映射的路径,通过这路径就可以从外部访问你的服务了,目的是为了不爆露你机器的IP,面向服务的路由了,给你选一个可用的出来, 17 path: /service-feign/** 18 serviceId: service-feign

启动我们的注册中心服务、至少一个服务提供者、启动Feign服务消费者、启动我们的Zuul服务消费者,启动正常:

打开浏览器器,输入http://localhost:8768/service-feign/hello?name=111这是我们基于Feign的请求转发

打开浏览器器,输入http://localhost:8768/service-feign/hi?name=111这是我们基于RestTemplate的请求转发

可以看到,我们成功将我们的路由请求转发到Feign服务消费者模块上了,接下来我们要实现以下Zuul对请求的拦截和熔断处理,

拦截就是在转发之前或者之后当请求到达Feign之前做拦截处理,这个是很重要的功能,熔断是当我们路由转发请求的服务不可用该怎么处理响应呢?

一、路由请求拦截

1package com.xu.serviceconsumer.component; 2 3import com.netflix.zuul.ZuulFilter; 4import com.netflix.zuul.context.RequestContext; 5import org.slf4j.Logger; 6import org.slf4j.LoggerFactory; 7import org.springframework.stereotype.Component; 8 9import javax.servlet.http.HttpServletRequest; 10 11@Component 12public class MyTokenFilter extends ZuulFilter { 13 14 private Logger logger = LoggerFactory.getLogger(MyTokenFilter.class); 15 16 //四种类型:pre,routing,error,post 17 //pre:主要用在路由映射的阶段是寻找路由映射表的 18 //routing:具体的路由转发过滤器是在routing路由器,具体的请求转发的时候会调用 19 //error:一旦前面的过滤器出错了,会调用error过滤器。 20 //post:当routing,error运行完后才会调用该过滤器,是在最后阶段的 21 @Override 22 public String filterType() { 23 return "pre"; 24 } 25 26 //自定义过滤器执行的顺序,数值越大越靠后执行,越小就越先执行 27 @Override 28 public int filterOrder() { 29 return 1; 30 } 31 32 //控制过滤器生效不生效,可以在里面写一串逻辑来控制 33 @Override 34 public boolean shouldFilter() { 35 return true; 36 } 37 38 //执行过滤逻辑 39 @Override 40 public Object run() { 41 42 RequestContext context = RequestContext.getCurrentContext(); 43 HttpServletRequest request = context.getRequest(); 44 String url = request.getRequestURL().toString(); 45 logger.info("请求URL:"+url); 46 String token = request.getParameter("name"); 47 if (token == null){ 48 context.setSendZuulResponse(false); 49 context.setResponseStatusCode(401); 50 context.setResponseBody("there is no request parameter name"); 51 52 53 return null; 54 } 55 return null; 56 } 57}

简单看一下代码知道这个过滤器继承了ZuulFilter,在run()方法里日志输出了请求的URL路径和对参数是否有name做了简单的拦截过滤,请求http://localhost:8768/service-feign/hello?

可以看到这个Zuul的路由过滤器成功的对这个请求拦截过滤了,最后看一下控制台信息也可以看到成功输出打印了请求的URL

二、路由熔断

1package com.xu.serviceconsumer.component; 2 3import org.springframework.cloud.netflix.zuul.filters.route.FallbackProvider; 4import org.springframework.http.HttpHeaders; 5import org.springframework.http.HttpStatus; 6import org.springframework.http.MediaType; 7import org.springframework.http.client.ClientHttpResponse; 8import org.springframework.stereotype.Component; 9 10import java.io.ByteArrayInputStream; 11import java.io.IOException; 12import java.io.InputStream; 13 14@Component 15public class MyFallbackProvider implements FallbackProvider { 16 17 @Override 18 public String getRoute() { 19 return "service-feign"; 20 } 21 22 @Override 23 public ClientHttpResponse fallbackResponse(String route, Throwable cause) { 24 System.out.println("route:"+route); 25 System.out.println("exception:"+cause.getMessage()); 26 return new ClientHttpResponse() { 27 @Override 28 public HttpStatus getStatusCode() throws IOException { 29 return HttpStatus.OK; 30 } 31 32 @Override 33 public int getRawStatusCode() throws IOException { 34 return 200; 35 } 36 37 @Override 38 public String getStatusText() throws IOException { 39 return "ok"; 40 } 41 42 @Override 43 public void close() { 44 45 } 46 47 @Override 48 public InputStream getBody() throws IOException { 49 return new ByteArrayInputStream(("Sorry, the service "+getRoute()+" is unavailable now.").getBytes()); 50 } 51 52 @Override 53 public HttpHeaders getHeaders() { 54 HttpHeaders headers = new HttpHeaders(); 55 headers.setContentType(MediaType.APPLICATION_JSON); 56 return headers; 57 } 58 }; 59 } 60}

注意这里的一段代码

我们的熔断路由器配置的是service-feign(就是我们zuul请求路由的这个这个服务),我们关闭这个服务,保留其他之前开启的服务,请求http://localhost:8768/service-feign/hi?name=111

自此,我们可以

自此,说明我们自定义的熔断器已经起作用了,这课的内容到此为止,下回再见!

===============================================================================

如果您觉得此文有帮助,可以打赏点钱给我支付宝或扫描二维码

点赞
收藏

评论区

加载中...

相关推荐

MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1

文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

MySQL部分从库上面因为大量的临时表tmp_table造成慢查询

背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_

皕杰报表之UUID

​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为

手写Java HashMap源码

HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22

springboot2.0下的zuul路由网关初探

Zuul作为微服务系统的网关组件,用于构建边界服务,致力于动态路由、过滤、监控、弹性伸缩和安全。为什么需要ZuulZuul、Ribbon以及Eureka结合可以实现智能路由和负载均衡的功能;网关将所有服务的API接口统一聚合,统一对外暴露。外界调用API接口时,不需要知道微服务系统中各服务相互调用的复杂性,保护了内部微服务单元的API接口;网关可以做