Spring Cloud Zuul
- 快速入门
- 构建网关
- 请求路由
- 请求过滤
- 路由详解
- 服务路由配置
- 服务路由的默认规则
- 本地跳转
- Cookie和头信息
- Hystrix和Ribbon支持
- 过滤器详解
- 过滤器
- 请求生命周期
- 禁用过滤器
快速入门
构建网关
API网关服务的构建过程
- 构建一个基础的Spring Boot工程,命名为api-gateway,修改pom.xml,引入
spring-cloud-starter-zuul
依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zuul</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
- 创建应用主类,使用@EnableZuulProxy注解开启Zuul的api网关服务功能
@EnableZuulProxy
@SpringBootApplication
public class HelloApplication {
public static void main(String[] args) {
SpringApplication.run(HelloApplication.class, args);
}
}
请求路由
- 在
application.properties
中配置Zuul应用的基础信息,指定Eureka注册中心的位置,并且配置服务路由
spring.application.name=api-gateway
server.port=5555
zuul.routes.api-a.path=/api-a/**
zuul.routes.api-a.serviceId=hello-service
zuul.routes.api-b.path=/api-b/**
zuul.routes.api-b.serviceId=feign-consumer
eureka.client.service-url.defaultZone=http://localhost:1111/eureka
启动服务后,查看eureka-server的信息面板,可以看到API-GATEWAY已经在列表中
经过配置,http://localhost:5555/api-a/hello
符合/api-a/**
的规则,最终/hello
的请求会被发送到hello-service
服务的某个实例上去
http://localhost:5555/api-b/feign-consumer
符合/api-b/**
的规则,最终/feign-consumer
的请求会被发送到feign-consumer
服务的某个实例上去
请求过滤
定义一个类来继承ZuulFilter抽象类并重写下面4个方法来实现自定义的过滤器
- filterType:过滤器的类型,决定过滤器在请求的哪个生命周期中执行,定义为pre,代表会在请求被路由之前执行
pre:可以在请求被路由之前调用
routing:在路由请求时被调用
post:在routing和error过滤器之后被调用
error:处理请求时发生错误时被调用 - filterOrder:过滤器的执行顺序.当请求在一个阶段中存在多个过滤器时,需要根据该方法返回的值来依次执行
- shouldFilter:判断该过滤器是否需要被执行,返回true表示该过滤器对所有请求都会生效
- run:过滤器的具体逻辑,对于不满足条件的请求可以有如下设置
//zuul过滤该请求,不对其路由
ctx.setSendZuulResponse(false);
//设置返回的错误码
ctx.setResponseStatusCode(401);
//对返回的body内容进行编辑
ctx.setResponseBody("Your request has been lost!");
在实现了自定义过滤器之后,并不会直接生效,还需要在主类中创建具体的Bean
@EnableZuulProxy
@SpringBootApplication
public class HelloApplication {
public static void main(String[] args) {
SpringApplication.run(HelloApplication.class, args);
}
@Bean
public AccessFilter accessFilter(){
return new AccessFilter();
}
}
总结Spring Cloud Zuul的优点:
1)作为系统的统一入口,屏蔽了系统内部各个微服务的细节
2)可以与服务治理框架结合,实现自动 化的服务实例维护以及负载均衡的路由转发
3)可以实现接口权限校验与微服务业务逻辑的解耦
4)通过服务网关中的过滤器,在各生命周期中去校验请求的内容,将原本在对外服务层做的校验前移,保证了微服务的无状态性,同时降低了微服务的测试难度,让服务本身更集中关注业务逻辑的处理
路由详解
服务路由配置
对于面向服务的路由配置,可以用zuul.routes.user-service=/user-service/**
来配置
在Eureka的帮助下,API网关服务自身就已经维护了系统中所有serviceId与实例地址的映射关系
服务路由的默认规则
Spring Cloud Zuul构建的API网关服务引入Spring Cloud Eureka之后,它为Eureka中的每个服务都自动创建一个默认路由规则
对于不希望对外开放的服务可以通过zuul.ignored-services
参数来设置一个服务名匹配表达式来定义不自动创建服务的规则,然后在配置文件中通过zuul.routes.<serviceId>=<path>
配置方式来创建路由,其他的依然是使用默认规则
本地跳转
在Zuul实现的API网关路由功能中,还支持forward形式的服务端跳转配置
zuul.routes.api-a.path=/api-a/**
zuul.routes.api-a.url=http://localhost:8001/
zuul.routes.api-b.path=/api-b/**
zuul.routes.api-b.url=forward:/local
当接收到/api-b/hello的请求,对于api-b
的路由规则生效,请求会被转发到网关的/local/hello请求上进行本地处理,所以需要增加一个/local/hello的接口实现才可以
@RestController
public class HelloController{
@RequestMapping("/local/hello")
public String hello(){
return "Hello World Local";
}
}
Cookie和头信息
- 通过指定路由的参数来配置,方法有两种
#方法一:对指定路由开启自定义敏感头
zuul.routes.<router>.customSensitiveHeaders=true
#方法二:将指定路由的敏感头设置为空
zuul.routes.<router>.sensitiveHeaders=
仅对指定的Web应用开启对敏感信息的传递,影响范围小,不至于引起其他服务的信息泄露问题
重定向问题描述:在登录完成后,通过重定向的方式跳到登录后的页面,指向了具体的服务实例地址
重定向问题解决方案:网关在进行路由转发之前为请求设置Host头信息,以标识最初的服务端请求地址,具体配置如下:
zuul.addHostHeader=true
Hystrix和Ribbon支持
Zuul拥有线程隔离和断路器自我保护功能,以及对服务调用的客户端负载均衡功能
当使用path和url的映射关系来配置路由的时候,不会采用HystrixCommand来包装,所以这类路由请求没有线程隔离和断路器的保护,并且也不会有负载均衡的能力.
所以,尽量使用path和serviceId的组合来进行配置,这样不仅保证API网关的健壮和稳定,也能用到Ribbon的客户端负载均衡功能
在使用Zuul搭建API网关的时候,可以通过Hystrix和Ribbon的参数来调整路由请求的各种超时时间等配置
在有些情况下,可能需要关闭重试机制,可以使用下面的配置:
#全局关闭重试机制
zuul.retryable=false
#指定路由关闭重试机制
zuul.routes.<route>.retryable=false
过滤器详解
过滤器
在Spring Cloud Zuul中实现的过滤器必须包含4个基本特征:过滤类型,执行顺序,执行条件,具体操作,具体含义前面已经讲过
String filterType();
int filterOrder();
boolean shouldFilter();
Object run();
请求生命周期
一个HTTP请求到达API网关之后,如何在各种不同类型的过滤器之间流转的详细过程
第一阶段pre:在进行请求路由之前做一些前置加工
第二阶段routing:将外部请求转发到具体服务实例上去的过程,当服务实例将请求结果都返回之后,routing阶段完成,请求进入第三阶段post
第三阶段post:此类型的过滤器在处理的时候不仅可以获取到请求信息,还能获取到服务实例的返回信息,所以在post类型的过滤器中,可以对处理结果进行一些加工或者转换等内容
特殊阶段error:此阶段只有上述三个阶段中发生异常时才会触发,但是最后的流向还是post过滤器,需要通过post过滤器将最终结果返回给请求客户端
禁用过滤器
对于过滤器不想使用了,想要禁用,在Zuul中特别提供了一个参数来禁用指定的过滤器,参数配置格式如下:
zuul.<SimpleClassName>.<filterType>.disable=true
其中<SimpleClassName>
代表过滤器的类名,比如AccessFilter<filterType>
代表过滤器类型,比如AccessFilter的pre类型
比如想要禁用AccessFilter过滤器,只要在application.properties配置文件中增加如下配置:zuul.AccessFilter.pre.disable=true
这样就可以禁用Spring Cloud Zuul中默认定义的核心过滤器,来实现一套更符合实际需求的处理机制