Spring Cloud Zuul (五)

API网关服务 Spring Cloud Zuul

API网关是一个更为智能的应用服务器,它的存在就像是整个微服务架构系统的门面,所有的外部客户端访问都需要经过它来进行调度和过滤。除了需要实现请求路由,负载均衡及校验过滤等功能外还需要与服务治理框架的结合,请求转发时的熔断机制,服务的聚合等一系列高级功能。

在Spring Cloud中提供了基于Netflix Zuul实现的API网关组件Spring Cloud Zuul。对于路由规则与服务实例的维护,Spring Cloud Zuul通过与Spring Cloud Eureka进行整合,将自身注册为Eureka治理下的应用,同时从Eureka获得了所有其他微服务的实例信息,使得将维护服务实例的工作交给了服务治理框架自动完成。不在需要人工介入。对于路由规则的维护,Zuul默认将通过以服务名作为ContextPath的方式创建路由映射。对于类似签名校验及登录校验,可以独立成一个单独的服务存在,只是它并不是给各个微服务调用,而是在API网关服务上进行统一调用来对微服务接口做前置过滤,实现对微服务接口的拦截和校验。Spring Cloud Zuul提供了一套过滤器机制,可以很好地支持这样的任务。

1. 快速集成 Spring Cloud Zuul

1.1 构建网关

  1. 创建基础Spring Boot工程

  2. 添加依赖: spring-cloud-starter-zuul

  3. 在主类上使用@EnableZuulProxy注解开启Zuul的API网关服务功能

  4. 配置Zuul应用的基础信息

    spring.application.name=api-gateway
    spring.port=8080
    

1.2 请求路由

启动Eureka服务注册中心和微服务应用

  • 传统路由方式

    对api-gateway服务增加路由配置规则

    zuul.routes.api-a-url.path=/api-a-url/**
    zuul.routes.api-a-url.url=http://localhost:8081/
    

    定义发往API网关的请求中,所有符合/api-a-url/**规则的访问都将被路由转发到http://localhost:8081/地址上。api-a-url部分为路由的名称,可任意定义,一组path与url映射关系的路由名要相同。

  • 面向服务的路由

    ​ Spring Cloud Zuul实现了与Spring Cloud Eureka的无缝整合,可以让路由的path不是映射具体的url,而是映射某个具体的服务,而具体的服务则交给Eureka的服务发现机制去自动维护,称之为面向服务的路由。

    1. 添加依赖:spring-cloud-starter-eureka

    2. 配置Zuul的Eureka注册中心的位置

    3. 配置服务路由

      zuul.routes.api-a.path=/api-a/**
      zuul.routes.api-a.serviceId=hello-service
      

      简洁配置方式

      zuul.routes.hello-service=/api-a/**
      

1.3 请求过滤

Zuul允许在API网关上通过定义过滤器实现对请求的拦截与过滤,只需要继承ZuulFilter抽象类并定义它的四个抽象函数。

public class AccessFilter extends ZuulFilter {
    /**
    * 过滤器类型,决定过滤器在请求的哪个生命周期执行
    */
    @Override
    public String filterType() {
        return "pre";
    }
    
    /**
    * 过滤器的执行顺序,当同一阶段存在多个过滤器时,需要根据该返回值指定执行顺序
    */
    @Override
    public int filterOrder() {
        return 0;
    }
    
    /**
    * 过滤器是否执行
    */
    @Override
    public boolean shouldFilter() {
        return true;
    }
    
    /**
    * 过滤器任务
    */
    @Override
    public Object run() {
        RequestContext ctx = RequestContext.getCurrentContext();
        HttpServletRequest request = ctx.getRequest();
        
        String token = request.getHeader("Authorization");
        
        if (token == null) {
            ctx.setSendZuulResponse(false);
            ctx.setResponseStatusCode(401);
            // ctx.setResponseBody(body);
        }
        
        return null;
    }
}

定义Zuul拦截器配置,并添加拦截器

@Configuration
public class ZuulFilterConfiguration {
    
    @Bean
    public AccessFilter accessFilter() {
        return new AccessFilter();
    }
}

2. 路由详解

2.1 服务路由配置

简洁配置方式

zuul.routes.hello-service=/api-a/**

2.2 服务路由默认规则

为Spring Cloud Zuul构建的API网关服务引入Spring Cloud Eureka之后,它为Eureka中的每个服务都自动创建一个默认路由规则,默认路由规则的path使用serviceId配置的服务名作为请求前缀,以hello-service为例:

zull.routes.hello-service.path=/hello-service/**
zull.routes.hello-service.serviceId=hello-service

2.3 路径匹配

在Spring Cloud Zuul中,路由匹配的路径表达式采用了Ant风格定义

通配符 说明
? 匹配任意单个字符
* 匹配任意数量字符
** 匹配任意数量字符,支持多级目录

2.4 忽略表达式

Spring Cloud Zuul忽略表达式参数zuul.ignored-patterns用来设置不希望被API网关进行路由的URL表达式。

zuul.ignored-patterns=/**/hello/**

2.5 Cookie与头信息

默认情况下,Spring Cloud Zuul请求路由时,会过滤掉HTTP请求头信息中的一些敏感信息,防止它们被传递到下游的外部服务器。默认的敏感头信息通过zuul.sensitiveheaders参数定义,包括Cookie, Set-Cookie, Authorization三个属性。

解决方案:

  • 设置全局参数为空覆盖默认值

    zuul.sensitiveheaders=
    
  • 设置指定路由的参数

    // 对指定路由开启自定义敏感头
    zuul.routes..customSensitiveHeaders=true
    // 将指定路由的敏感头设置为空
    zuul.routes..sensitiveheaders=
    

2.6 Hystrix与Ribbon支持

Zuul自身包含了对Hystrix和Ribbon的模块依赖,因此Zuul拥有线程隔离和断路器的自我保护功能,以及对服务调用的客户端负载均衡功能。当使用path和url的映射关系配置路由规则时没有上述功能,因此使用Zuul时尽量使用path和serviceId的组合进行配置。参数配置如下:

ribbon:
  ReadTimeout: 600000      // 设置路由转发请求的超时时间
  ConnectTimeout: 600000   // 设置路由转发请求,创建请求连接的超时时间
hystrix:
  command:
    default:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 60000  // 设置API网关路由转发请求HystrixCommand执行超时时间

2.7 过滤器详解

在Zuul中,路由功能真正运行时,它的路由映射和请求转发由几个不同的过滤器完成。路由映射主要通过pre类过滤器完成,它将请求路径与配置的路由规则进行匹配,找到需要转发的路由地址。请求转发的部分由route类过滤器完成。

在Spring Cloud Zuul中实现的过滤器必须包含4个基本特征:过滤类型,执行顺序,执行条件,具体操作。实际上它们就是ZuulFilter接口中定义的4个抽象方法:

String filterType();
int filterOrder();
boolean shouldFilter();
Object run();
  • filterType:过滤器类型
    • pre:可以再请求被路由前调用
    • routing:在路由请求时被调用
    • post:在routing和error过滤器之后被调用
    • error:处理请求时发生错误时被调用
  • filterOrder:过滤器执行顺序,数值越小优先级越高
  • shouldFilter:是否执行过滤器
  • run:过滤逻辑

2.8 异常处理

在Spring Cloud Zuul中,在HTTP请求生命周期的各个阶段默认实现了一批核心过滤器,在API网关服务启动的时候被自动加载和启用,但核心过滤器中没有实现error阶段的过滤器,因此需要在自定义过滤器中处理异常内容:

  • try-catch处理

    error相关三个主要参数:

    1. error.status_code:错误码
    2. error.exception:Exception异常对象
    3. error.message:错误信息(优先级高于Exception对象中的message)
    public Object run() {
        RequestContext ctx = RequestContext.getCurrentContext();
        
        try {
            // TODO
        } catch (Exception exception) {
            ctx.set("error.status_code", HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
            ctx.set("error.exception", exception);
        }
        
        return null;
    }
    
  • ErrorFilter处理

    在请求生命周期的pre,route,post三个阶段有异常抛出的时候都会进入到error阶段处理,通过创建error类型过滤器捕获异常信息并处理。

    public Object run() {
        RequestContext ctx = RequestContext.getCurrentContext();
        Throwable throwable = ctx.getThrowable();
        
        ctx.set("error.status_code", HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
        ctx.set("error.exception", throwable.getCause());
        
        return null;
    }
    

你可能感兴趣的:(Spring Cloud Zuul (五))