Spring Cloud(十):服务网关Zuul高级特性

Posted by Kaka Blog on March 26, 2019

上篇文章介绍了Spring Cloud Zuul基本的使用方法,但其实Zuul还有更多的应用场景,比如:鉴权、流量转发、请求统计等等,这些功能都可以使用Zuul来实现。

img

Zuul过滤器

Filter是Zuul的核心,用来实现对外服务的控制。Filter的生命周期有4个,分别是PREROUTINGPOSTERROR

Zuul大部分功能都是通过过滤器来实现的,这些过滤器类型对应于请求的典型生命周期。

  • PRE: 这种过滤器在请求被路由之前调用。我们可利用这种过滤器实现身份验证、在集群中选择请求的微服务、记录调试信息等。
  • ROUTING:这种过滤器将请求路由到微服务。这种过滤器用于构建发送给微服务的请求,并使用Apache HttpClient或Netfilx Ribbon请求微服务。
  • POST:这种过滤器在路由到微服务以后执行。这种过滤器可用来为响应添加标准的HTTP Header、收集统计信息和指标、将响应从微服务发送给客户端等。
  • ERROR:在其他阶段发生错误时执行该过滤器。 除了默认的过滤器类型,Zuul还允许我们创建自定义的过滤器类型。例如,我们可以定制一种STATIC类型的过滤器,直接在Zuul中生成响应,而不将请求转发到后端的微服务。

应用场景:

  • token校验/安全认证
  • 动态修改请求参数,比如:终端发过来的数据,出于安全要求,可能是经过加密处理的,需要在网关层进行参数解密,再传递到后面的服务;再比如:用户传过来的token值,需要转换成userId/userName这些信息,再传递到背后的微服务。
  • 灰度发布(Gated Launch/Gray Release):将请求(根据参数内容+业务规则),将其转向到特定的灰度机器上。Spring Cloud MicroService中有一个metadata-map(元数据)设置,可以很好的满足这类需求。

熔断处理

当我们的后端服务出现异常的时候,我们不希望将异常抛出给最外层,期望服务可以自动进行一降级。Zuul给我们提供了这样的支持。当某个服务出现异常时,直接返回我们预设的信息。

我们通过自定义的fallback方法,并且将其指定给某个route来实现该route访问出问题的熔断处理。主要实现FallbackProvider接口来实现,FallbackProvider默认有两个方法,一个用来指明熔断拦截哪个服务,一个定制返回内容。

@Component
public class RouteFallback implements FallbackProvider {
    @Override
    public String getRoute() {
        return "*";
    }

    @Override
    public ClientHttpResponse fallbackResponse(String route, Throwable cause) {
        return new ClientHttpResponse() {
            @Override
            public HttpStatus getStatusCode() throws IOException {
                return HttpStatus.OK;
            }

            @Override
            public int getRawStatusCode() throws IOException {
                return 200;
            }

            @Override
            public String getStatusText() throws IOException {
                return "OK";
            }

            @Override
            public void close() {

            }

            @Override
            public InputStream getBody() throws IOException {
                return new ByteArrayInputStream(JSONObject.toJSONString(ResponseGenerator.error(ErrorCodeEnum.CUSTOM_ERROR.getCode(), "服务不可用")).getBytes());
            }

            @Override
            public HttpHeaders getHeaders() {
                HttpHeaders headers = new HttpHeaders();
                headers.setContentType(MediaType.APPLICATION_JSON);
                return headers;
            }
        };
    }
}
  • getRoute()*表示所有的服务

限流

限制请求的频率,比如验证码接口可以限制1分钟内只能请求3次。

代码实现:

1、导入依赖

<dependency>
    <groupId>com.marcosbarbero.cloud</groupId>
    <artifactId>spring-cloud-zuul-ratelimit</artifactId>
    <version>2.2.3.RELEASE</version>
</dependency>
  • 注意版本问题,网上很多例子是1.3.2,由于我的Spring Boot版本是2.0.3,所以需要使用2.2.3版本。

2、修改配置问题

zuul.ratelimit.enabled=true
zuul.ratelimit.repository=consul # 用来存储统计信息,可以是redis
zuul.ratelimit.policy-list.pay-server[0].limit=3 # 单位时间内允许访问的次数
zuul.ratelimit.policy-list.pay-server[0].refresh-interval=60 # 单位时间设置
zuul.ratelimit.policy-list.pay-server[0].type=origin # 对IP进行限流
  • default-policy 可选 - 针对所有的路由配置的策略,除非特别配置了policy-list
  • policy-list 对特定的服务id进行限流
  • policy-list.pay-server[0]需要加上下标,不然会报错

3、启动服务和网关,请求多次后会返回There was an unexpected error (type=Too Many Requests, status=429).,到consul页面,可以看到Key/Value里有值。

参考