路由和过滤:Zuul
路由是微服务架构不缺少的一部分。例如“/”可能映射到web服务,“/api/users”映射到用户管理服务,而“/api/shop”映射到采购服务。Zuul是Netflix中的一个基于JVM的路由器,也是一个服务端负载均衡器。
zuul有下列用途:
- Authentication(权限验证)
- Insights
- Stress Testing(压力测试)
- Canary Testing(金丝雀测试)
- Dynamic Routing(动态路由)
- Service Migration(服务迁移)
- Load Shedding(负载削减)
- Security(安全机制)
- Static Response handling(静态响应处理)
- Active/Active traffic management(流量管理)
注意:
1)zuul.max.host.connections已经被zuul.host.maxTotalConnections(默认值200)和zuul.host.maxPerRouteConnections(默认值20)代替了。
2)Hystrix对所有理由的默认隔离模式是SEMAPHORE,可以通过zuul.ribbonIsolationStrategy改为THREAD。
Embedded Zuul Reverse Proxy(反向代理)
Spring Cloud创建了一个内置Zuul代理来简化开发,比如有一个UI应用想要使用代理调用后端的一个或者多个服务。这可以避免为后台每个服务都配置CORS和权限系统。
在spring boot的入口类上使用@EnableZuulProxy注解来开启代理。代理使用Ribbon通过服务发现来定位后端服务实例。并且所有请求在 hystrix command中执行。所以当断路器打开时,代理将不会重试连接后端服务。
注意:Zuul starter不包含服务发现客户端,所以想要使用服务发现功能,需要提供一个服务发现客户端(比如Eureka)。
为了防止自动添加服务,可以设置zuul.ignored-services参数来避免。如果一个服务匹配到一个忽略表达式,并且又在路由映射中明确指定了,那么它就不会被忽略。例如(application.yml):
application.yml配置:
#用于开发环境
spring:
application:
name: zuul-consmr-srv #ServiceId, 配置服务命名,不区分大小写,在注册中心管理界面默认大写显示
server:
port: 18090
eureka:
client:
service-url:
defaultZone: http://peer1:8000/eureka/,http://peer2:8001/eureka/,http://peer3:8002/eureka/
pom引入zuul:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
ZUUL启动类:
package com.clsaa.learn.zuul;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
/**
* 使用@EnableZuulProxy注解激活zuul。
* 该注解可以看到该注解整合了@EnableCircuitBreaker、@EnableDiscoveryClient,
* 是个组合注解,目的是简化配置。
*/
@EnableZuulProxy
@SpringBootApplication
public class ZuulApplication {
public static void main(String[] args) {
SpringApplication.run(ZuulApplication.class,args);
}
}
ZUUL路由配置详解:
1. 自定义指定微服务的访问路径
producer微服务会被映射到/myproducer/**路径, 即: 访问http://localhost:18090/myproducer/1, 会映射到http://producer/myproducer/1
zuul:
routes:
producer: /myproducer/** # producer是某个微服务的serviceId
2. 忽略指定微服务
忽略服务非常简单, 可以使用zuul.ignored-services配置需要忽略的服务,多个用逗号分隔。例如:
zuul:
ignored-services: provider,consumer
忽略掉provider,consumer两个微服务,只代理其它微服务。
3. 忽略所有微服务,只路由指定微服务
zuul:
ignored-services: '*' # 使用'*'可忽略所有微服务
routes:
provider: /user/** # 只路由provider微服务(provider为serviceId)
注意: 这个路由规则使用到Ribbon + Hystrix,走的是使用的Zuul过滤器是RibbonRoutingFilter
4. 同时指定微服务的serviceId和对应路径,例如:
#该配置效果同示例1
zuul:
routes:
provider-router: # 路由名称,名字可以任意起
service-id: provider
path: /user/** # service-id对应的路径
5. 同时指定path和URL,例如:
zuul:
routes:
provider-router: # 路由名称,名字可以任意起
url: http://localhost:8000 #指定url
path: /user/** # service-id对应的路径
这样就可以将/user/**映射到http://localhost:8000/** 。
注意:使用这种方式配置路由,不会作为HystrixCommand执行,同时也不能使用Ribbon来负载均衡多个URL。
即:用不上Ribbon也用不上Hystrix,Zuul过滤器走的是SipleRoutingFilter
。
例6可解决该问题。
6. 同时指定path和URL,并且不破坏Zuul的Hystrix、Ribbon特性。
zuul:
routes:
provider-router: # 路由名称,名字可以任意起
service-id: provider
path: /user/** # service-id对应的路径
ribbon:
eureka:
enabled: false # 为Ribbon禁用Eureka
provider # service-id
ribbon:
listOfServers: localhost:8000,localhost:8001
#这样既可以指定path与URL,又不破坏Zuul的Hystrix与Ribbon的特性
7. 使用正则表达式指定Zuul的路由匹配规则
借助PatternServiceRouteMapper,实现从微服务到映射路由的正则配置。例如
通过这段代码即可实现将诸如provider-v1这个微服务, 映射到/v1/provider/**这个路径。
package com.itmuch.cloud.study;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
import org.springframework.cloud.netflix.zuul.filters.discovery.PatternServiceRouteMapper;
import org.springframework.context.annotation.Bean;
@SpringBootApplication
@EnableZuulProxy
public class ZuulApplication {
public static void main(String[] args) {
SpringApplication.run(ZuulApplication.class, args);
}
@Bean
public PatternServiceRouteMapper serviceRouteMapper() {
// 调用构造函数PatternServiceRouteMapper(String servicePattern, String routePattern)
// servicePattern 指定微服务的正则
// routePattern 指定路由正则
return new PatternServiceRouteMapper("(?<name>^.+)-(?<version>v.+$)",
"${version}/${name}");
}
}
8. 路由前缀
示例1, 访问Zuul的/api/provider/1路径, 请求将会被转发到provider的/api/1
zuul:
prefix: /api
strip-prefix: false # 去除代理前缀
routes:
provider: /user/** # provider为service-id
#注:
# 1. 要向所有映射添加前缀,请将zuul.prefix设置为一个值,例如/ api。 默认情况下,
# 在转发请求之前,从请求中删除代理前缀(使用zuul.stripPrefix = false关闭此行为)。
# 2. prefix和stripPrefix(依赖于prefix的使用)连用影响是全局的
# 3. path和stripPrefix连用影响是局部的
示例2, 访问Zuul的/user/1路径, 请求将会被转发到provider的/user/1
zuul:
routes:
provider: # service-id
path: /user/** # provider为service-id
strip-prefix: false # 去除代理前缀
9. 忽略某些路径
想让Zuul代理某个微服务,同时又想保护该微服务的某些敏感路径, 可使用ignoredPatterns,指定忽略的正则。例如:
zuul:
ignoredPatterns: /**/admin/** # 忽略所有包含/admin/的路径
routes:
provider: /user/** # provider -- serviceId
10. 敏感Header设置
一般同一个系统服务之间共享Header,但应尽量防止一些敏感的Header外泄。很多场景下,需要通过路由指定一系列敏感Header列表。例如:
为微服务provider指定敏感Header。
zuul:
routes:
provider: # provider -- serviceId
path: /users/**
sensitive-headers: Cookie, Set-Cookie,Authorization
url: https://downstream
也可全局指定敏感Header,例如:
zuul:
sensitive-headers: Cookie, Set-Cookie,Authorization
# 默认是Cookie, Set-Cookie,Authorization
# 需要注意: 使用zuul.routes.{serviceId}.sensitive-headers 配置方式配置, 会覆盖掉上述全局配置
11. 忽略Header
zuul:
ignored-headers: Header1, Header2 # 默认为空
# 设置后, Header1, Header2 将不会传播到其它微服务中
# 如果Spring Security在项目的classpath中时,zuul.ignored-headers的默认值
# 是: Pragma,Cache-Control,X-Frame-Options,X-content-Type-Options,X-XSS-Protection,
# Expires。如果下游微服务需要这些Header, 可以设置zuul.ignoreSecurityHeaders: false.