⑤SpringCloud 实战:引入Zuul组件,开启网关路由
这是SpringCloud实战系列中第4篇文章,了解前面第两篇文章更有助于更好理解本文内容:
①SpringCloud 实战:引入Eureka组件,完善服务治理
②SpringCloud 实战:引入Feign组件,发起服务间调用
③SpringCloud 实战:使用 Ribbon 客户端负载均衡
④SpringCloud 实战:引入Hystrix组件,分布式系统容错
简介
Zuul 也是 Netflix OSS 中的一员,是一个基于 JVM 路由和服务端的负载均衡器,支持动态路由、监控、弹性和安全等特性。Spring Cloud 会创建一个嵌入式 Zuul 代理来简化一个常见用例的开发,比如用户程序可能会对一个或多个后端服务进行调用,引入 Zuul 网关能有效避免为所有后端独立管理CORS和身份验证问题的需求
Zuul的使用了一系列的过滤器,这些过滤器可以完成以下功能:
- 身份验证和安全性
识别每个资源的身份验证要求,并拒绝不满足这些要求的请求。 - 审查与监控
跟踪有意义的数据和统计数据,以便给我们一个准确的生产视图。 - 动态路由
根据需要将请求动态路由到不同的后端集群。 - 压力测试
逐渐增加集群的流量,以评估性能。 - 负载消减
为每种类型的请求分配容量,并丢弃超出限制的请求。 - 静态响应处理
直接在边缘构建一些响应,而不是将它们转发到内部集群Zuul 的使用
实战 Zuul
搭建 zuul
新建一个新的项目
jlw-zuul
引入zuul依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
启动类上加入注解
@EnableZuulProxy
引入Eureka注册中心,并注册上去
现在不需要额外配置就可以启动了,启动之后你会看到默认的服务映射相关日志:
Mapped URL path [/eureka-provider-temp/**] onto handler of type [class org.springframework.cloud.netflix.zuul.web.ZuulController]
Mapped URL path [/eureka-server/**] onto handler of type [class org.springframework.cloud.netflix.zuul.web.ZuulController]
Mapped URL path [/eureka-provider/**] onto handler of type [class org.springframework.cloud.netflix.zuul.web.ZuulController]
Mapped URL path [/ribbon-client/**] onto handler of type [class org.springframework.cloud.netflix.zuul.web.ZuulController]
Mapped URL path [/eureka-client/**] onto handler of type [class org.springframework.cloud.netflix.zuul.web.ZuulController]
然后就可以通过zuul网关来访问后端服务了
管理端点
Zuul 默认依赖了 actuator,并且会暴露/actuator/routes
和/actuator/filters
两个端点,访问这两个断点,可以很直观的查看到路由信息,在查看之前需要添加以下配置:
# 应该包含的端点ID,全部:*
management.endpoints.web.exposure.include: *
访问http://127.0.0.1:8000/actuator可以查看所有端点信息,访问http://127.0.0.1:8000/actuator/routes 可查看到路由信息:
路由配置
为网关添加前缀
# 访问网关的时候必须要加的路径前缀
zuul.prefix = /api
添加以上配置后,访问网关时路径必须是/api/**,然后才会正确的路由到后端对应的服务
如果在转发请求到服务的时候要去掉这个前缀,可以设置strip-prefix= false来忽略
# 请求转发前是否要删除 zuul.prefix 设置的前缀 ,true:转发前要带上前缀(默认值),fasle:不带上前缀
zuul.routes.ecs.strip-prefix = true
配置路由
# 忽略注册中心 eureka-server,*:会忽略所有的服务
zuul.ignored-services = eureka-server,eureka-client
# eureka-client 服务映射规则,http://127.0.0.1:8000/ec/sayHello
zuul.routes.eureka-client = /ec/**
上面的配置会忽略eureka-server和eureka-client,访问http://127.0.0.1:8000/api/ec/**
的请求的都会被路由到eureka-client,如果没有忽略eureka-client,则访问/eureka-client/**
和/ec/**
都会路由到eureka-client服务。
注意/ec/*
只会匹配一个层级,/ec/**
会匹配多个层级。
指定服务id和path
# 指定service-id和path
zuul.routes.rcs.service-id = ribbon-client
zuul.routes.rcs.path = /rc/**
然后访问http://127.0.0.1:8000/api/rc/queryPort接口就会被路由到ribbon-client
服务
路由配置顺序
如果想按照配置的顺序进行路由规则控制,则需要使用YAML,如果是使用propeties文件,则会丢失顺序。例如:
zuul:
routes:
users:
path: /myusers/**
legacy:
path: /**
使用propeties文件,旧的路径可能出现在用户路径的前面,从而导致用户路径无法访问。
关闭重试
可以通过将zuul.retryable设置为false来关闭Zuul的重试功能,默认值也是false。
zuul.retryable=false
还可以通过将zuul.routes.routename.retryable设置为false来禁用逐个路由的重试功能
# 关闭指定路由的重试
zuul.routes.ecs.retryable = false
忽略服务路由
添加以下配置会忽略指定的服务,很明显注册中心一般是不需要通过网关来访问的,所以需要忽略它
# 忽略注册中心 eureka-server,*:会忽略所有的服务
zuul.ignored-services = eureka-server
也可以通过zuul.ignoredPatterns
来配置你不想暴露出去的API
隔离策略
设置信号量
# 改为信号量隔离
zuul.ribbon-isolation-strategy=semaphore
# Hystrix的最大总信号量
zuul.semaphore.max-semaphores=1000
# 单个路由可以使用的最大连接数
zuul.host.max-per-route-connections=500
最大总信号量默认是100,单个路由最大的连接数默认是20,有时候并发量上不去可能就是使用的默认配置。
设置独立的线程池
Zuul 中默认采用信号量隔离机制,如果想要换成线程,需要配置 zuul.ribbon-isolation-strategy=THREAD
,配置后所有的路由对应的 Command 都在一个线程池中执行,这样其实达不到隔离的效果,所以我们需要增加一个 zuul.thread-pool.use-separate-thread-pools 的配置,让每个路由都使用独立的线程池,zuul.thread-pool.thread-pool-key-prefix 可以为线程池配置对应的前缀,方便调试。
## 线程隔离
#zuul.ribbon-isolation-strategy=THREAD
## 每个路由使用独立的线程池
#zuul.thread-pool.use-separate-thread-pools=true
## 线程池前缀
#zuul.thread-pool.thread-pool-key-prefix=zuul-pool-
其他配置
更换Http客户端
Zuul默认使用的是 Apache HTTP Client,需要更换的话只需要设置对应的属性即可
# Ribbon RestClient
ribbon.restclient.enabled=true
# or okhttp
ribbon.okhttp.enabled=true
Cookie和请求头
Zuul 提供了一个敏感头属性配置,设置了该属性后,Zuul 就不会把相关的请求头转发到下游的服务,比如:
# 请求头里面的字段不会带到eureka-client服务
zuul.routes.ecs.sensitive-headers = jinglingwang
sensitiveHeaders 的默认值是Cookie、Set-Cookie、Authorization,如果把该值配置成空值,则会把所有的头都传递到下游服务。
还可以通过设置zuul.sensitiveHeaders来设置全局的敏感标头。 如果在路由上设置了sensitiveHeaders,它将覆盖全局的sensitiveHeaders设置
忽略请求头
除了对路由敏感的标头单独设置之外,还可以设置一个名为zuul.ignoredHeaders的全局值,比如:
# 该配置的Header也不会转发到下游服务
zuul.ignored-headers=jinglingwang
在默认情况下是没有这个配置的,如果项目中引入了Spring Security,那么Spring Security会自动加上这个配置,默认值为: Pragma,Cache-Control,X-Frame-Options,X-Content-Type-Options,X-XSS-Protection,Expries。
下游服务需要使用Spring Security的Header时,可以增加zuul.ignoreSecurityHeaders=false
的配置
文件上传
通过Zuul网关上传文件时,只要文件不大,都可以正常的上传,对于大文件,Zuul有一个替代路径(/zuul/*
)可以绕过Spring DispatcherServlet,比如你的文件服务(file-service)路由配置是zuul.routes.file-service=/file/**
,然后你post提交文件到/zuul/file/**
即可。
还有一种办法就是直接修改可上传文件大小的配置:
# 文件最大值。值可以使用后缀“ MB”或“ KB”分别表示兆字节或千字节
spring.servlet.multipart.max-file-size=10MB
# 最大请求大小
spring.servlet.multipart.max-request-size=30MB
两种办法都需要在文件服务里面添加以上的配置
在上传大文件时也需要设置合理的超时时间:
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds: 60000
ribbon:
ConnectTimeout: 3000
ReadTimeout: 60000
自定义过滤器
过滤器是 Zuul 中的核心内容,很多高级的扩展都需要自定义过滤器来实现,在 Zuul 中自定义一个过滤器只需要继承 ZuulFilter,然后重写 ZuulFilter 的四个方法即可:
@Component
public class LogFilter extends ZuulFilter{
/**
* 返回过滤器的类型,可选值有 pre、route、post、error 四种类型
* @return
*/
@Override
public String filterType(){
return "pre";
}
/**
* 指定过滤器的执行顺序,数字越小,优先级越高
* 默认的filter的顺序可以在FilterConstants类中查看。
* @return
*/
@Override
public int filterOrder(){
// pre filter
return PRE_DECORATION_FILTER_ORDER - 1 ;
// ROUTE filter
//return SIMPLE_HOST_ROUTING_FILTER_ORDER - 1 ;
// POST filter
//return SEND_RESPONSE_FILTER_ORDER - 1 ;
}
/**
* 决定了是否执行该过滤器,true 为执行,false 为不执行
* @return
*/
@Override
public boolean shouldFilter(){
return true;
}
/**
* 如果shouldFilter()为true,则将调用此方法。该方法是ZuulFilter的核心方法
* @return 返回值会被忽略
* @throws ZuulException
*/
@Override
public Object run() throws ZuulException{
HttpServletRequest req = (HttpServletRequest) RequestContext.getCurrentContext().getRequest();
System.out.println("ZUUL REQUEST:: " + req.getScheme() + " " + req.getRemoteAddr() + ":" + req.getRemotePort() + " uri::"+ req.getRequestURI()) ;
return null;
}
}
禁用过滤器
Zuul 默认提供了很多过滤器(ZuulFilter),有关可启用的过滤器列表,可以参考Zuul 过滤器的包(netflix.zuul.filters)。如果要禁用一个过滤器,可以按照zuul.<SimpleClassName>.<filterType>.disable=true
格式来进行设置,比如:
zuul.SendResponseFilter.post.disable=true
跨域支持
如果是外部网页应用需要调用网关的 API,不在同一个域名下则会存在跨域的问题,想让Zuul处理这些跨域的请求,可以通过提供自定义WebMvcConfigurer bean来完成:
@Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
/**
* 配置跨源请求处理
* @param registry
*/
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/path/**")
.allowedOrigins("https://jinglingwang.cn")
.allowedMethods("GET", "POST");
}
};
}
上面的示例中,允许jinglingwang.cn
的GET
和POST
方法将跨域请求发送到 /path/**开头的端点
Zuul 超时
有两种情况:
如果Zuul使用服务发现,则需要配置Ribbon的属性配置超时
ribbon.ReadTimeout
ribbon.SocketTimeout
如果通过指定URL配置了Zuul路由
# 套接字超时(以毫秒为单位)。默认为10000
zuul.host.socket-timeout-millis=15000
# 连接超时(以毫秒为单位)。默认为2000
zuul.host.connect-timeout-millis=3000
服务容错与回退
Spring Cloud 中,Zuul 默认整合了 Hystrix,当Zuul中给定路由的电路跳闸时,可以通过创建FallbackProvider类型的bean提供回退响应。配置示例代码如下:
@Component
public class EurekaClientFallbackProvider implements FallbackProvider{
@Override
public String getRoute(){
// 路由的server-id,* or null:为所有的路由都配置回退
return "eureka-client";
}
@Override
public ClientHttpResponse fallbackResponse(String route,Throwable cause){
if (cause instanceof HystrixTimeoutException) {
return response(HttpStatus.GATEWAY_TIMEOUT);
} else {
return response(HttpStatus.INTERNAL_SERVER_ERROR);
}
}
private ClientHttpResponse response(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("eureka-client 服务暂不可用,jinglingwang请你稍后重试!".getBytes());
}
@Override
public HttpHeaders getHeaders(){
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON_UTF8);
return headers;
}
};
}
}
重启后,运行效果如下:
如果要为所有路由提供默认回退,getRoute方法返回*或null即可。
Ribbon client延迟加载
Zuul内部使用Ribbon来调用远程URL。 默认情况下,Ribbon 客户端在第一次调用时由Spring Cloud进行延迟加载。可以通过以下配置来开启启动时立即加载:
zuul.ribbon.eager-load.enabled=true
@EnableZuulProxy vs @EnableZuulServer
Spring Cloud Netflix安装了很多过滤器,具体取决于用于启用Zuul的注解。 @EnableZuulProxy是@EnableZuulServer的超集。换句话说,@ EnableZuulProxy包含@EnableZuulServer安装的所有过滤器。 “proxy”中的其他过滤器启用路由功能。 如果需要一个“空白”的 Zuul,则应使用@EnableZuulServer。
⑤SpringCloud 实战:引入Zuul组件,开启网关路由的更多相关文章
- ⑥SpringCloud 实战:引入gateway组件,开启网关路由功能
这是SpringCloud实战系列中第4篇文章,了解前面第两篇文章更有助于更好理解本文内容: ①SpringCloud 实战:引入Eureka组件,完善服务治理 ②SpringCloud 实战:引入F ...
- SpringCloud微服务(05):Zuul组件,实现路由网关控制
本文源码:GitHub·点这里 || GitEE·点这里 一.Zuul组件简介 1.基础概念 Zuul 网关主要提供动态路由,监控,弹性,安全管控等功能.在分布式的微服务系统中,系统被拆为了多个微服务 ...
- ⑦SpringCloud 实战:引入Sleuth组件,完善服务链路跟踪
这是SpringCloud实战系列中第7篇文章,了解前面第两篇文章更有助于更好理解本文内容: ①SpringCloud 实战:引入Eureka组件,完善服务治理 ②SpringCloud 实战:引入F ...
- 跟我学SpringCloud | 第十七篇:服务网关Zuul基于Apollo动态路由
目录 SpringCloud系列教程 | 第十七篇:服务网关Zuul基于Apollo动态路由 Apollo概述 Apollo相比于Spring Cloud Config优势 工程实战 示例代码 Spr ...
- SpringCloud实战-Zuul网关服务
为什么需要网关呢? 我们知道我们要进入一个服务本身,很明显我们没有特别好的办法,直接输入IP地址+端口号,我们知道这样的做法很糟糕的,这样的做法大有问题,首先暴露了我们实体机器的IP地址,别人一看你的 ...
- ④SpringCloud 实战:引入Hystrix组件,分布式系统容错
这是SpringCloud实战系列中第4篇文章,了解前面第两篇文章更有助于更好理解本文内容: ①SpringCloud 实战:引入Eureka组件,完善服务治理 ②SpringCloud 实战:引入F ...
- 21.SpringCloud实战项目-后台题目类型功能(网关、跨域、路由问题一文搞定)
SpringCloud实战项目全套学习教程连载中 PassJava 学习教程 简介 PassJava-Learning项目是PassJava(佳必过)项目的学习教程.对架构.业务.技术要点进行讲解. ...
- ②SpringCloud 实战:引入Feign组件,完善服务间调用
这是SpringCloud实战系列中第二篇文章,了解前面第一篇文章更有助于更好理解本文内容: ①SpringCloud 实战:引入Eureka组件,完善服务治理 简介 Feign 是一个声明式的 RE ...
- springcloud 实战 网关zuul使用中遇到的相关问题
springcloud 实战 网关zuul使用中遇到的相关问题 1.网关zuul使用时,跨域问题在网关中配置pre过滤器: response.setHeader("Access-Contr ...
随机推荐
- 1. 安装虚拟机,Hadoop和Hive
由于想自学下Hive,所以前段时间在个人电脑上安装了虚拟机,并安装上Hadoop和Hive.接下我就分享下我如何安装Hive的.步骤如下: 安装虚拟机 安装Hadoop 安装Java 安装Hive 我 ...
- 使用Selenium爬取京东电商数据(以手机商品为例)
进入京东(https://www.jd.com)后,我如果搜索特定的手机产品,如oppo find x2,会先出现如下的商品列表页: 如果点击进入其中一个商品会进入到如下图所示的商品详情页,可以看到用 ...
- Fastdfs集群部署以及基本操作
FastDFS引言 本地存储与分布式文件系统 本地存储的缺点: 是否有备份? 没有 成本角度? 贵 服务器 :用于计算 ---- cpu/内存 用于存储 ---- 硬盘大 存储瓶颈? 容量有限 ...
- ssh连接客户端一段时间没响应就断掉的解决办法-保持长连接
修改(添加)server端的 /etc/ssh/sshd_config #server每隔60秒发送一次请求给client,然后client响应,从而保持连接 ClientAliveInterval ...
- JAVA程序员工作常用英语(细心整理)
基础----进阶 A. array数组accessible 可存取的 area面积audio 音频 addition 加法 action 行动 arithmetic 算法adjustment 调整 a ...
- 微服务通信之feign的配置隔离
前言 由上文我们知道针对某一个Feign接口,我们可以给他设置特定的配置类.那如果现在有一个服务,我们只想对A服务配置一个拦截器拦截请求而不影响其他服务,那应该怎么做呢? 一.feign接口配置 由前 ...
- Andrew Ng 机器学习公开课 - 线性回归
我的机器学习系列从现在开始将会结合Andrew Ng老师与sklearn的api是实际应用相结合来写了. 吴恩达(1976-,英文名:Andrew Ng),华裔美国人,是斯坦福大学计算机科学系和电子工 ...
- Javaer 进阶必看的 RocketMQ ,就这篇了
每个时代,都不会亏待会学习的人. 大家好,我是 yes. 继上一篇 头条终面:写个消息中间件 ,我提到实现消息中间件的一些关键点,今天就和大家一起深入生产级别消息中间件 - RocketMQ 的内核实 ...
- PDF技术 -Java实现Html转PDF文件
转载:https://blog.csdn.net/qq_34190023/article/details/82999702 html转换为pdf的关键技术是如何处理网页中复杂的css样式.以及中文乱码 ...
- 解决Ubuntu配置nginx出现的问题
Ubuntu18.04配置nginx出现的各种错误 缺少pcre库 编译nginx 出现错误 安装pcre库,出现错误 手动编译安装pcre库 (1)下载并解压pcre库 wget https://f ...