Spring Cloud 之 Zuul.
Spring Cloud 之 Zuul.
Spring Cloud 之 Zuul.
阅读目录
一、概述
二、准备阶段
三、请求转发
四、请求过滤
五、Hystrix 和 Ribbon 支持
回到顶部
一、概述
API 网关是一个更为智能的应用服务器,它的定义类似于面向对象设计模式中的 Facade 模式,它的存在就像是整个微服务架构系统的门面一样,所有的外部客户端访问都需要经过它来进行调度和过滤。它除了要实现请求路由、负载均衡、校验过滤等功能之外,还需要更多能力,比如与服务治理框架的结合、请求转发时的熔断机制、服务的聚合等一系列高级功能。
在 Spring Cloud 中了提供了基于 Netflix Zuul 实现的 API 网关组件 Spring Cloud Zuul。
回到顶部
二、准备阶段
SpringBoot 版本号:2.1.6.RELEASE
SpringCloud 版本号:Greenwich.RELEASE
pom.xml
<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-netflix-eureka-client</artifactId> </dependency> </dependencies>
application.yml
server:
port: 5555
spring:
application:
name: cloud-zuul
eureka:
client:
service-url: defaultZone: http://user:password@localhost:1111/eureka/
ZuulApplication.java
// 开启 Zuul 的Api 网关服务功能
@EnableZuulProxy
@EnableDiscoveryClient
@SpringBootApplication
public class ZuulApplication {
public static void main(String[] args) { SpringApplication.run(ZuulApplication.class, args); }
}
回到顶部
三、请求转发
Spring Cloud Zuul 通过与 Spring Cloud Eureka 进行整合,将自身注册为 Eureka 服务治理下的应用,同时从 Eureka 中获得了所有其他微服务的实例信息。这样的设计非常巧妙地将服务治理体系中维护的实例信息利用起来,使得将维护服务实例的工作交给了服务治理框架自动完成,不再需要人工介入。而对于路由规则的维护, Zuul 默认会将通过以服务名作为
ContextPath 的方式来创建路由映射。比如上面的配置,Spring Cloud Zuul 会为 Eureka 中的每个服务都自动创建一个默认路由规则,默认规则的 path 会使用 serviceId 配置的服务名作为请求前缀 —— 对于 /'serviceId'/** 的请求,会被转发到 serviceId 的服务处理。
可以设置不对每个服务自动创建路由规则吗?
zuul:
# Zuul 将对所有的服务都不自动创建路由规则
ignored-services: "*"
如果我们手动配置路由是怎样的呢?推荐下面的方式:
zuul:
routes:
client-2: path: /client-2/** serviceId: cloud-eureka-client # zuul.routes.<serviceid> = <path> cloud-eureka-client: /client-3/** client-4: path: /client-4/** # 请求转发 —— 仅限转发到本地接口 url: forward:/local
其中, ?:匹配任意单个数量字符;:匹配任意多个数量字符;*:匹配任意多个数量字符,支持多级目录。
不推荐使用 url 的方式来配置路由,该请求是直接通过 httpClient 包实现的, 而没有使用 Hystrix 命令进行包装, 所以这类请求并没有线程隔离和断路器的保护。
如果我们要过滤掉某些 url,让它不走路由规则呢?
zuul:
# 对某些 url 设置不经过路由选择
ignored-patterns: {"//world/","//zuul/"}
Spring Cloud Zuul 对 "/zuul" 的路径访问的会绕过 dispatcherServlet, 被 ZuulServlet 处理,主要用来应对处理大文件上传的情况。
zuul:
servlet-path: /zuul
回到顶部
四、请求过滤
Spring Cloud Zuul 提供了一套过滤器机制,开发者可以通过使用 Zuul 来创建各种校验过滤器,然后指定哪些规则的请求需要执行校验逻辑,只有通过校验的才会被路由到具体的微服务接口,不然就返回错误提示。
要在 Zuul 实现过滤器机制也很简单,只需要继承 ZuulFilter 类即可。接下来,我们来写一个过滤器 TokenFilter,校验接口参数中是否有 token 参数。
@Component
public class TokenFilter extends ZuulFilter {
private Logger logger = LoggerFactory.getLogger(TokenFilter.class); /** * 过滤器的类型,它决定过滤器在请求的哪个生命周期中执行。这里定义为 pre, 代表会在请求被路由之前执行。路由类型有下面几种: * <p> * - pre: 可以在请求被路由之前调用。 * - routing: 在路由请求时被调用。 * - post: 在 routing 和 error 过滤器之后被调用。 * - error: 处理请求时发生错误时被调用。 * * @return */ @Override public String filterType() { return FilterConstants.PRE_TYPE; } /** * 过滤器的执行顺序。当请求在一个阶段中存在多个过滤器时,需要根据该方法返回的值来依次执行,数值越小,优先级越高。 * * @return */ @Override public int filterOrder() { return 0; } /** * 判断该过滤器是否需要被执行。这里我们直接返回了true, 因此该过滤器对所有请求都会生效。实际运用中我们可以利用该函数来指定过滤器的有效范围。 * * @return */ @Override public boolean shouldFilter() { return true; } /** * 过滤器的具体执行逻辑 * * @return * @throws ZuulException */ @Override public Object run() throws ZuulException { RequestContext ctx = RequestContext.getCurrentContext(); HttpServletRequest request = ctx.getRequest(); logger.info("send {} request to {}", request.getMethod(), request.getRequestURL().toString()); String token = request.getParameter("token"); if (StringUtils.isEmpty(token)) { logger.warn("token is empty"); // 令 zuul 过滤该请求,不对其进行路由 ctx.setSendZuulResponse(false); // 设置返回的错误码 ctx.setResponseStatusCode(401); // 设置返回的 body ctx.setResponseBody(""); return null; } logger.info("access token is ok"); return null; }
}
实际上,上面提到的 Zuul 路由功能在真正运行时,它的路由映射和请求转发都是由几个不同的过滤器完成的。所以,过滤器可以说是 Zuul 实现 API 网关功能最为核心的部件,每一个进入 Zuul 的 HTTP 请求都会经过一系列的过滤器处理链得到请求响应并返回给客户端。下图源自 Zuul 的官方Wiki 中关于请求生命周期的图解, 它描述了一个 HTTP 请求到达 API 网关之后, 如何在各种不同类型的过滤器之间转的详细过程。
当外部 HTTP 请求到达 API 网关服务的时候,首先它会进入第一个阶段 pre, 在这里它会被 pre 类型的过滤器进行处理, 该类型过滤器的主要目的是在进行请求路由之前做一些前置加工,比如请求的校验、限流等。在完成了 pre 类型的过滤器处理之后,请求进入第二个阶段 routing, 也就是之前说的路由请求转发阶段,请求将会被 routing 类型过滤器处理。这里的具体处理内容就是将外部请求转发到具体服务实例上去的过程,当服务实例将请求结果都返回之后,routing 阶段完成, 请求进入第三个阶段 post。此时请求将会被 post 类型的过滤器处理,这些过滤器在处理的时候不仅可以获取到请求信息,还能获取到服务实例的返回信息,所以在 post 类型的过滤器中,我们可以对处理结果进行一些加工或转换等内容。另外,还有一个特殊的阶段 error, 该阶段只有在上述三个阶段中发生异常的时候才会触发,但是它的最后流向还是 post 类型的过滤器,因为它需要通过 post 过滤器将最终结果返回给请求客户端。
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 处理正常的请求响应
我们可以在配置文件中,选择是否禁用某个过滤器。
zuul:
# 禁用某个过滤器 zuul...disable=true
TokenFilter:
pre: disable: true
常常 request 中有些 header 信息我们不希望渗透到服务中去,比如 accessToken、sign、Cookie 等。或者我们要保持 request 的 host 信息一致,该怎么配置呢?
zuul:
routes:
client-2: path: /client-2/** serviceId: cloud-eureka-client # 敏感头信息设置为空,表示不过滤敏感头信息,允许敏感头信息渗透到下游服务器(针对单个服务的敏感头部信息配置,下面两个配置项选其一即可) sensitiveHeaders: "" customSensitiveHeaders: true
# Spring Cloud Zuul在请求路由时,会过滤掉 HTTP 请求头(Cookie、Set-Cookie、Authorization)信息中的一些敏感信息,
sensitive-headers: {"Cookie", "Set-Cookie", "Authorization"}
# 网关在进行路由转发时为请求设置 Host 头信息(保持在路由转发过程中 host 头信息不变)
add-host-header: true
# 请求转发时加上 X-Forwarded-*头域
add-proxy-headers: true
回到顶部
五、Hystrix 和 Ribbon 支持
该参数可以用来设置 API 网关中路由转发请求的 HystrixCommand 执行超时时间,单位为毫秒。
hystrix:
command:
default: execution: isolation: thread: timeoutinMilliseconds: 5000
ribbon:
# 该参数用来设置路由转发请求的时候,创建请求连接的超时时间。
ConnectTimeout: 500
# 该参数用来设置路由转发请求的超时时间。
ReadTimeout: 2000
# 最大自动重试次数
MaxAutoRetries: 1
# 最大自动重试下一个服务的次数
MaxAutoRetriesNextServer: 1
其中,Hystrix 的配置参数可以在 HystrixCommandProperties.java 中找到。
其中,Ribbon 的配置参数可以在 CommonClientConfigKey.java 中找到。
另外需要注意的是,请求重试还需要将 zuul.retryable 设置为 true。
原文地址https://www.cnblogs.com/jmcui/p/11219820.html
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
阿里P8谈Java工程师怎么进大厂?你没进大厂就是这四个问题!
“怎样才能进大厂?” “我是一个二本计算机专业的程序员,怎样才能进大厂?” “我是一个非计算机专业的工程师,有机会可以进大厂吗?” 我收到不少咨询如何进大厂的问题,以上是一些比较典型的提问。 进大厂的可能性是因人而异的,有些人基础好,能力强,概率会大很多;有些人底子差,自然会更难。由于咨询这个问题的同学比较多,接下来,我就说说大家关心的几点吧。 关于学历 大厂和学历,这个是咨询的最多的问题。一般大厂对学历是有最低要求的,都会要求本科及以上,非本科的同学不是说完全没有机会,但确实会很难。 有些岗位的要求还会更高,比如机器学习,应用研究类的岗位,因为专业方向本身的原因,一般都要研究生学历。 对于大部分的工程岗位,比如前端,客户端,后台等,一般本科就可以过学历槛了。 接下来说说 985, 211 和 非985,非211。说实话,学校的优势是肯定存在的,因为简历很多,学校作为筛选条件之一,是相对客观的,所以好的学校肯定是存在优势的。 我记得前面有同学留言,说自己大学学了很多东西,但因为是二本,最后连面试资格都没有。如果这位同学看到这篇文章,觉得自己的能力不错,可以联系我,发简历给我,我相信人才...
- 下一篇
聊聊架构、内存拷贝、Swift 新特性: iOS 面试场景复习题 ,20190720
以下进入捏的场景,小明去面试 第一题: 怎样展现小明仅有的架构能力 问:你怎么做 iOS 组件化的? 小明想,代码写起来爽,不就行了 程序员要提供一点数据结构 答:CTMediate (同一份代码,各人理解,存在差异。以下是个人观点,该官方博客,没看的,建议看下。那篇的许多观点,下文不作引用) 为什么要组件化?随着项目代码的庞大,机器性能不够,人力来凑。如果机器性能很好,项目一秒钟 run 起来。组件化的必要性,可能少了一些。当然还有做动态插件化,与大项目好分组、分功能开发等优势。 没组件化的时候,模块 A 调用模块 B, 需要在 A 中,import B.A 才能知道 B 暴露的方法,去使用 B 提供的能力。 现在要实现组件化,就不好相互 import , 循环引用。 这个时候,就是靠约定。组件化开发,感觉画风一变,UI 层变网络层,和同事约定接口的事情多一些 组件化,要解耦,基本功能就是组件之间的传值,与回调,要清爽 小明画了一个 CTMediate 的架构图 Mediate 负责具体的实现部分,就像一个黑盒,把约定的功能给执行了,把结果给返回出去。 执行方法分三个方面,targe...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- Docker使用Oracle官方镜像安装(12C,18C,19C)
- CentOS7,CentOS8安装Elasticsearch6.8.6
- CentOS6,CentOS7官方镜像安装Oracle11G
- CentOS7编译安装Cmake3.16.3,解决mysql等软件编译问题
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果
- CentOS8编译安装MySQL8.0.19
- SpringBoot2配置默认Tomcat设置,开启更多高级功能
- Windows10,CentOS7,CentOS8安装Nodejs环境
- Docker快速安装Oracle11G,搭建oracle11g学习环境
- CentOS8,CentOS7,CentOS6编译安装Redis5.0.7