这是SpringCloud实战系列中第4篇文章,了解前面第两篇文章更有助于更好理解本文内容:

①SpringCloud 实战:引入Eureka组件,完善服务治理

②SpringCloud 实战:引入Feign组件,发起服务间调用

③SpringCloud 实战:使用 Ribbon 客户端负载均衡

④SpringCloud 实战:引入Hystrix组件,分布式系统容错

简介

Zuul 也是 Netflix OSS 中的一员,是一个基于 JVM 路由和服务端的负载均衡器,支持动态路由、监控、弹性和安全等特性。Spring Cloud 会创建一个嵌入式 Zuul 代理来简化一个常见用例的开发,比如用户程序可能会对一个或多个后端服务进行调用,引入 Zuul 网关能有效避免为所有后端独立管理CORS和身份验证问题的需求

Zuul的使用了一系列的过滤器,这些过滤器可以完成以下功能:

  • 身份验证和安全性

    识别每个资源的身份验证要求,并拒绝不满足这些要求的请求。
  • 审查与监控

    跟踪有意义的数据和统计数据,以便给我们一个准确的生产视图。
  • 动态路由

    根据需要将请求动态路由到不同的后端集群。
  • 压力测试

    逐渐增加集群的流量,以评估性能。
  • 负载消减

    为每种类型的请求分配容量,并丢弃超出限制的请求。
  • 静态响应处理

    直接在边缘构建一些响应,而不是将它们转发到内部集群Zuul 的使用

实战 Zuul

搭建 zuul

  1. 新建一个新的项目jlw-zuul

  2. 引入zuul依赖

    <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
    </dependency>
  3. 启动类上加入注解@EnableZuulProxy

  4. 引入Eureka注册中心,并注册上去

  5. 现在不需要额外配置就可以启动了,启动之后你会看到默认的服务映射相关日志:

    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]
  6. 然后就可以通过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.cnGETPOST方法将跨域请求发送到 /path/**开头的端点

Zuul 超时

有两种情况:

  1. 如果Zuul使用服务发现,则需要配置Ribbon的属性配置超时

    ribbon.ReadTimeout
    ribbon.SocketTimeout
  2. 如果通过指定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组件,开启网关路由的更多相关文章

  1. ⑥SpringCloud 实战:引入gateway组件,开启网关路由功能

    这是SpringCloud实战系列中第4篇文章,了解前面第两篇文章更有助于更好理解本文内容: ①SpringCloud 实战:引入Eureka组件,完善服务治理 ②SpringCloud 实战:引入F ...

  2. SpringCloud微服务(05):Zuul组件,实现路由网关控制

    本文源码:GitHub·点这里 || GitEE·点这里 一.Zuul组件简介 1.基础概念 Zuul 网关主要提供动态路由,监控,弹性,安全管控等功能.在分布式的微服务系统中,系统被拆为了多个微服务 ...

  3. ⑦SpringCloud 实战:引入Sleuth组件,完善服务链路跟踪

    这是SpringCloud实战系列中第7篇文章,了解前面第两篇文章更有助于更好理解本文内容: ①SpringCloud 实战:引入Eureka组件,完善服务治理 ②SpringCloud 实战:引入F ...

  4. 跟我学SpringCloud | 第十七篇:服务网关Zuul基于Apollo动态路由

    目录 SpringCloud系列教程 | 第十七篇:服务网关Zuul基于Apollo动态路由 Apollo概述 Apollo相比于Spring Cloud Config优势 工程实战 示例代码 Spr ...

  5. SpringCloud实战-Zuul网关服务

    为什么需要网关呢? 我们知道我们要进入一个服务本身,很明显我们没有特别好的办法,直接输入IP地址+端口号,我们知道这样的做法很糟糕的,这样的做法大有问题,首先暴露了我们实体机器的IP地址,别人一看你的 ...

  6. ④SpringCloud 实战:引入Hystrix组件,分布式系统容错

    这是SpringCloud实战系列中第4篇文章,了解前面第两篇文章更有助于更好理解本文内容: ①SpringCloud 实战:引入Eureka组件,完善服务治理 ②SpringCloud 实战:引入F ...

  7. 21.SpringCloud实战项目-后台题目类型功能(网关、跨域、路由问题一文搞定)

    SpringCloud实战项目全套学习教程连载中 PassJava 学习教程 简介 PassJava-Learning项目是PassJava(佳必过)项目的学习教程.对架构.业务.技术要点进行讲解. ...

  8. ②SpringCloud 实战:引入Feign组件,完善服务间调用

    这是SpringCloud实战系列中第二篇文章,了解前面第一篇文章更有助于更好理解本文内容: ①SpringCloud 实战:引入Eureka组件,完善服务治理 简介 Feign 是一个声明式的 RE ...

  9. springcloud 实战 网关zuul使用中遇到的相关问题

    springcloud 实战  网关zuul使用中遇到的相关问题 1.网关zuul使用时,跨域问题在网关中配置pre过滤器: response.setHeader("Access-Contr ...

随机推荐

  1. ubuntu18.04下stlink的一种安装方法

    安装前准备: 从软件包存储库中安装以下软件包: git gcc或clang或mingw32-gcc或mingw64-gcc(C编译器:很可能已经存在gcc) build-essential (在基于D ...

  2. sed1

    Linux sed命令 Linux 命令大全Linux sed命令是利用script来处理文本文件.sed可依照script的指令,来处理.编辑文本文件.Sed主要用来自动编辑一个或多个文件:简化对文 ...

  3. 查看ceph集群被哪些客户端连接

    前言 我们在使用集群的时候,一般来说比较关注的是后台的集群的状态,但是在做一些更人性化的管理功能的时候,就需要考虑到更多的细节 本篇就是其中的一个点,查询ceph被哪些客户端连接了 实践 从接口上来说 ...

  4. matlab 第五章单元数组、字符串作业

    1.创建 2×2 单元数组,第 1.2 个元素为字符串,第三个元素为整型变量,第四个元素为双精度(double)类型,并将其用图形表示. A=cell(2,2); A(1,1)={'mat'}; A( ...

  5. netcore一键部署到linux服务器以服务方式后台运行

    @font-face { font-family: octicons-link; src: url("data:font/woff;charset=utf-8;base64,d09GRgAB ...

  6. Linux权限位(含特殊权限位s s t) 及chown\chmod命令使用

    1.普通权限位 ls –l查看文件的属性 [root@oldboy ~]# ls -l -rw-------. 1 root root 1073 Mar 4 22:08 anaconda-ks.cfg ...

  7. Pinpoint 编译环境搭建(Pinpoint系列一)

    本文基于 Pinpoint 2.1.0 版本 目录 一.2.1.0 版本特性 二.编译环境准备 三.编译注意事项 四.编译目录 五.注意事项 新版本的内容参考官方文档, Pinpoint的整个搭建是历 ...

  8. DOM XSS详解

    DOM XSS简介 DOM XSS与反射性XSS.存储型XSS的主要区别在于DOM XSS的XSS代码不需要服务端解析响应的直接参与,触发XSS的是浏览器端的DOM解析. DOM XSS复现 环境搭建 ...

  9. 如何使用iMindMap制作更专业的时间计划

    时间计划无论是在日常生活中,还是在工作中,都显得极为重要.小到每周的购物时间规划,大到大型项目的时间管理,时间计划都会如影随形.虽然时间计划很重要,但很多人都会忽视这种重要性,可能只会在台本日历上作一 ...

  10. FL Studio音乐编曲入门教程

    有很多小伙伴给我们留言说使用FL Studio20一段时间后,虽然对这款音乐编曲软件的功能有了一个了解,但对它整个的编曲过程还不是太熟悉.所以今天我就给大家带来了FL Studio20这款音乐编曲软件 ...