1 Zuul 简介
在微服务架构中,如果让客户端直接和各个微服务直接通信的话,会产生很多问题,比如:客户端需要多次请求不同的微服务;对每个服务都要设立认证;难以重构,如果微服务需要重新划分,客户端也要作出相应的修改...要解决这些问题,我们可以在客户端和微服务之间设立一个中间层——微服务网关,网关对微服务接口进行了封装,微服务只跟网关进行交互,使得客户端和微服务的耦合度降低。
Zuul是Netflix开源的微服务网关,其核心是一系列的过滤器,通过这些过滤其,我们可以实现身份认证、动态路由等功能。
2 如何使用Zuul
- 引入相应的依赖:
org.springframework.cloud
spring-cloud-starter-eureka
org.springframework.cloud
spring-cloud-starter-zuul
- 在启动类中添加
@EnableZuulProxy
注解
@EnableZuulProxy
@SpringBootApplication
public class GatewayZuulApplication {
public static void main(String[] args) {
SpringApplication.run(GatewayZuulApplication.class, args);
}
}
- 编写配置文件,将Zuul服务注册到Eureka Server
server:
port: 8007
spring:
application:
name: gateway-zuul
eureka:
client:
service-url:
defaultZone: http://localhost:8001/eureka/
instance:
prefer-ip-address: true
3 路由配置
默认配置
如果没有在配置文件中对路由进行配置,那么默认将对http://ZUUL_HOST:ZULL_PORT/CONTEXT-PATH/serviceId/**
的请求转发到serviceId对应的微服务为指定微服务设置访问路径:
使用zuul.routes.指定微服务的serviceId=访问路径
进行设置,比如:
zuul:
routes:
ribbon-demo: /ribbon/**
- 还可以为每一个serviceId-path对设置别名,如:
zuul:
routes:
ribbon-route:
sevice-id: ribbon-demo
path: /ribbon/**
该设置与2中效果一致。
- 如果要禁止默认的路由配置,使用
zuul.ignored-services
进行设置,比如禁用所有的默认路由:
zuul:
ignored-services: '*'
- 指定URL和path:
zuul:
routes:
ribbon-route:
url: http://localhost:8003/
path: /ribbon/**
使用该方法指定的路由不会具有Hystrix和Ribbon的特性,如果要具有Hystrix和Ribbon的特性,要为Ribbon禁用Eureka,用listOfServers来指定url:
zuul:
routes:
ribbon-route:
serviceId: ribbon-demo
path: /ribbon/**
ribbon:
eureka:
enabled: false
ribbon-demo:
ribbon:
listOfServers: localhost:8003
- 路由转发可以带上前缀,有两种方式:
方式1:
zuul:
routes:
ribbon-route:
serviceId: ribbon-demo
path: /ribbon/**
strip-prefix: false
方式2:
zuul:
prefix: /ribbon
strip-prefix: false
routes:
ribbon-route:
serviceId: ribbon-demo
path: /ribbon/**
以上两种方法都是将请求转发到ribbon-demo的/ribbon/**
4 过滤器
4.1 过滤器分类
Zuul的核心是一系列的过滤器,过滤器主要分为四种:
- PRE,在请求被转发出去之前执行。
- ROUTING,将请求转发到微服务。
- POST,在请求转发之后执行。
- ERROR,在发生错误的时候执行。
4.2 自定义过滤器
- 编写一个类继承
ZuulFilter
并实现其中的抽象方法。
public class AccessFilter extends ZuulFilter {
@Override
public String filterType() {
return FilterConstants.PRE_TYPE;
}
@Override
public int filterOrder() {
return 0;
}
@Override
public boolean shouldFilter() {
return true;
}
@Override
public Object run() {
RequestContext requestContext = RequestContext.getCurrentContext();
HttpServletRequest request = requestContext.getRequest();
Object accessToken = request.getParameter("accessToken");
if (accessToken == null) {
requestContext.setSendZuulResponse(false);
requestContext.setResponseStatusCode(401);
return null;
}
return null;
}
}
-
filterType()
: 返回过滤器的类型,过滤器的类型有pre、 route、 post、 error等等,可以使用org.springframework.cloud.netflix.zuul.filters.support.FilterConstants
中的常量进行指定,该类提供了关于ZuulFilter的各种常量。 -
filterOrder()
: 返回过滤器执行的顺序。 -
shouldFilter()
: 判断过滤器是否需要执行。 -
run()
: 过滤器的具体逻辑。
- 在启动类中为过滤器创建具体的Bean。
@Bean
public AccessFilter accessFilter() {
return new AccessFilter();
}
4.3 禁用过滤器
禁用过滤器的话使用zuul.
,比如要禁用上面编写的自定义过滤器,可使用如下配置:
zuul:
AccessFilter:
pre:
disable: true
5 回退
在Spring Cloud中,Zuul默认集成了Hystrix, 如果要为其编写回退方法,可按如下方法,实现ZuulFallbackProvider
接口,指定要为哪个微服务提供回退,并提供一个ClientHttpResponse
作为响应。
@Component
public class RibbonDemoFallbackProvider implements ZuulFallbackProvider {
@Override
public String getRoute() {
return "eureka-client-demo";
}
@Override
public ClientHttpResponse fallbackResponse() {
return new ClientHttpResponse() {
@Override
public HttpStatus getStatusCode() throws IOException {
return HttpStatus.SERVICE_UNAVAILABLE;
}
@Override
public int getRawStatusCode() throws IOException {
return this.getStatusCode().value();
}
@Override
public String getStatusText() throws IOException {
return this.getStatusCode().getReasonPhrase();
}
@Override
public void close() {
}
@Override
public InputStream getBody() throws IOException {
return new ByteArrayInputStream("服务不可用!".getBytes());
}
@Override
public HttpHeaders getHeaders() {
HttpHeaders httpHeaders = new HttpHeaders();
MediaType mt = new MediaType("application", "json", Charset.forName("UTF-8"));
httpHeaders.setContentType(mt);
return httpHeaders;
}
};
}
}
6 端点
Zuul提供了两个端点来查看路由和过滤器信息:/routes
和/filters
,不过要先设置management.security.enabled=false
7 安全和Header
7.1 敏感Header
在进行路由时,有一些敏感Header不能外泄,可以使用下面配置进行设置:
zuul:
routes:
users:
path: /myusers/**
sensitiveHeaders: Cookie,Set-Cookie,Authorization
url: https://downstream
或者可以进行全局的配置:
zuul:
sensitiveHeaders: Cookie,Set-Cookie,Authorization
routes:
users:
path: /myusers/**
url: https://downstream
前者的配置会覆盖后者的全局配置。另外sensitiveHeaders: Cookie,Set-Cookie,Authorization
是默认的Header设置,如果不希望使用该配置,可以让该项的值为空,如 sensitiveHeaders:
7.2 忽略Header
可以在请求转发的时候丢弃一些Header:
zuul:
ignored-headers: Header1,Header2
默认情况下ignored-headers
为空值,但是如果Spring Security在项目的classpath中,默认值将会变化,如果需要将这些Headers传递下去,则要将zuul.ignoredSecurity-Headers
设置为false