欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Zuul——微服务网关

程序员文章站 2022-06-03 20:26:01
...

1 Zuul 简介

在微服务架构中,如果让客户端直接和各个微服务直接通信的话,会产生很多问题,比如:客户端需要多次请求不同的微服务;对每个服务都要设立认证;难以重构,如果微服务需要重新划分,客户端也要作出相应的修改...要解决这些问题,我们可以在客户端和微服务之间设立一个中间层——微服务网关,网关对微服务接口进行了封装,微服务只跟网关进行交互,使得客户端和微服务的耦合度降低。
Zuul是Netflix开源的微服务网关,其核心是一系列的过滤器,通过这些过滤其,我们可以实现身份认证、动态路由等功能。

2 如何使用Zuul

  1. 引入相应的依赖:
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-zuul</artifactId>
        </dependency>
  1. 在启动类中添加@EnableZuulProxy注解
@EnableZuulProxy
@SpringBootApplication
public class GatewayZuulApplication {

    public static void main(String[] args) {
        SpringApplication.run(GatewayZuulApplication.class, args);
    }
}
  1. 编写配置文件,将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 路由配置

  1. 默认配置
    如果没有在配置文件中对路由进行配置,那么默认将对 http://ZUUL_HOST:ZULL_PORT/CONTEXT-PATH/serviceId/**的请求转发到serviceId对应的微服务

  2. 为指定微服务设置访问路径:
    使用zuul.routes.指定微服务的serviceId=访问路径进行设置,比如:

zuul:
  routes: 
    ribbon-demo: /ribbon/**
  1. 还可以为每一个serviceId-path对设置别名,如:
zuul:
  routes:
    ribbon-route:
      sevice-id: ribbon-demo
      path: /ribbon/**

该设置与2中效果一致。

  1. 如果要禁止默认的路由配置,使用zuul.ignored-services进行设置,比如禁用所有的默认路由:
zuul:
  ignored-services: '*'
  1. 指定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. 路由转发可以带上前缀,有两种方式:
    方式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 自定义过滤器

  1. 编写一个类继承 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(): 过滤器的具体逻辑。
  1. 在启动类中为过滤器创建具体的Bean。
    @Bean
    public AccessFilter accessFilter() {
        return new AccessFilter();
    }

4.3 禁用过滤器

禁用过滤器的话使用zuul.<SimpleClassName>.<filterType>.disable=true,比如要禁用上面编写的自定义过滤器,可使用如下配置:

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