路由网关Zuul

作者: 董二弯 | 来源:发表于2019-06-07 19:09 被阅读3次

本章讲解构建微服务的另一个组件——智能网关组件Zuul。Zuul用于构建边界服务,致力于动态路由、过滤、监控、弹性伸缩和安全。

为什么需要Zuul

  • 能和ribbon、eureka相结合实现智能路由和负载均衡的功能。
  • 将所有服务的API接口统一聚合并对外界暴露。给外部的感觉是一个单体系统,这样保护了各个微服务的接口。
  • 可以做用户身份验证和权限认证,对微服务起到保护作用。
  • 可以实现监控功能,对请求进行记录。
  • 可以实现流量监控,在高流量下对服务降级。
  • api聚合,方便做测试。

工作原理

image.png

如图,zuul的核心是一系列过滤器,对自定义的ZuulServlet(类似于spring mvc的DispatcherServlet)来对请求进行控制,经过过滤后返回请求。Zuul包括以下4种过滤器:

  • PRE过滤器:路由到具体服务之前执行。可以做安全校验、身份验证、参数验证等。
  • ROUTING过滤器:用于路由到具体服务。默认使用HttpClient。
  • POST过滤器:路由到服务之后执行。用于收集统计信息、指标、以及将相应信息传输到客户端。
  • ERROR过滤器:其他过滤器发生错误时执行。
    过滤器之间通过RequestContext对象共享数据。过滤器有以下特性
  • Type(类型): 过滤器类型,决定在那个阶段起作用。
  • Execution Order(执行顺序):order值越小,越先执行。
  • Criteria(标准):过滤器执行所需的条件。
  • Action(行动):如果符合执行条件,则执行Action逻辑代码。

案列实战

搭建Zuul服务

在之前项目上新建一个Modul——api-gateway。

  • 添加pom依赖,主要包括zuul、eureka、web等的起步依赖。
<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>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
        </dependency>
  • 在启动类上加上@EnableZuulProxy开启zuul的功能,@EnableEurekaClient开启EurekaClient的功能。
@SpringBootApplication
@EnableEurekaClient
@EnableZuulProxy
public class ApiGatewayApplication {

    public static void main(String[] args) {
        SpringApplication.run(ApiGatewayApplication.class, args);
    }

}
  • 工程配置

spring:
  application:
    name: api-gateway
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/
server:
  port: 5000
zuul:
  routes:
    hiapi:
      path: /hiapi/**
      serviceId: eureka-client

重点说Zuul的配置写法。zuul.routes.hiapi.path: /hiapi/**,zuul.routes.hiapi.serviceId:eureka-client。表示可以将 “/hiapi”开头的url路由到eureka-client,其中的“hiapi”时自定义的。如果服务存在多个实例,Zuul会结合Ribbon做负载均衡。

  • 测试
    依此启动工程eureka-server,eureka-client启动两个实例,端口为8763,8764。
多次访问 http://localhost:5000/hiapi/hi?name = dzy
会交替出现
      hi dzy ,I am from 8763
      hi dzy ,I am from 8764
可见实现了路由并做了负载均衡。

注意
如果不需要负载均衡,可以指定服务实例的Url,用zuul.routes.hiapi.url配置,配置后直接访问指定的Url,在实际开发中很少用到。

zuul:
  routes:
    hiapi:
      path: /hiapi/**
      url: http://localhost:8763

如果想指定Url,并且想做负载均衡,可以自己维护负载均衡的列表

zuul:
  routes:
    hiapi:
      path: /hiapi/**
      serviceId: hiapi-v1  # 自定义服务名
  ribbon:
    eureka:
      enabled: false   # 不从Eureka Client获取服务注册列表信息。
  hiapi-v1:   #使用自定义服务名,配置多个负载均衡的url
    ribbon:
      listOfServers: http://localhost:8763,http://localhost:8764

如果想给服务的api接口加前缀,例如http://localhost:5000/v1/hiapi/hi?name = dzy,加一个v1作为版本号。这时需要用zuul.perfix的配置

zuul:
  routes:
    hiapi:
      path: /hiapi/**
      serviceId: eureka-client
  prefix: /v1

在Zuul上配置熔断器

需要实现ZuulFallbackProvider接口。实现改接口中的两个办法,一个是getRoute()方法,用于指定熔断功能用于那些路由的服务;另一个是fallbackResponse()为进入熔断功能是执行的逻辑。ZuulFallbackProvider源码如下

public interface ZuulFallbackProvider {

    /**
     * The route this fallback will be used for.
     * @return The route the fallback will be used for.
     */
    public String getRoute();

    /**
     * Provides a fallback response.
     * @return The fallback response.
     */
    public ClientHttpResponse fallbackResponse();
}

现实现一个针对eureka-client服务的熔断器,当eureka-client的服务出现故障时,进入熔断逻辑。代码如下

@Component
public class HystrixProvider implements ZuulFallbackProvider {

    @Override
    public String getRoute() {
       //所有的路由都加熔断功能,返回*
        return "*";
    }

    @Override
    public ClientHttpResponse fallbackResponse() {
        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("error! I am fallback".getBytes());
            }

            @Override
            public HttpHeaders getHeaders() {
                HttpHeaders headers = new HttpHeaders();
                headers.setContentType(MediaType.APPLICATION_JSON);
                return headers;
            }
        };
    }
}

注意:这里一定要加@Component把熔断器注入IOC容器。

Zuul使用过滤器

之前讲了Zuul的工作原理就是一系列过滤器。下面讲解如何实现一个自定义的过滤器。只需要继承ZuulFilter,并实现ZuulFilter中的抽象方法和IZuulFilter接口中的方法,其中filterType()为过滤器的类型;filterOrder()为过滤顺序,为一个Int类型的值,值越小,越早执行。shouldFilter()表示是否执行过滤逻辑,true则执行run()方法,false则不执行run()方法。其中run()写具体的过滤的逻辑。
现在实现检查请求中的参数是否传了token这个参数,如果没有传,请求不被路由到具体的服务实例,直接返回响应。代码如下:

@Component
public class MyFilter extends ZuulFilter {
    private static final Logger LOGGER = LoggerFactory.getLogger(MyFilter.class);

    @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 context = RequestContext.getCurrentContext();
        HttpServletRequest request = context.getRequest();
        String token = request.getParameter("token");
        if (StringUtils.isEmpty(token)) {
            LOGGER.info("token is not exist");
            context.setSendZuulResponse(false);
            context.setResponseStatusCode(401);
            try {
                context.getResponse().getWriter().write( "token is required");
            } catch (IOException e) {
                LOGGER.error(e.getMessage());
            }
        }
        return null;
    }
}

注意:这里一定要加@Component把filter注入IOC容器。

总结

在这一章学习了搭建了Zuul服务,并介绍了Zuul的工作原理和添加熔断器、过滤器。在下一章学习构建微服务中的配置中心——Spring Cloud Config组件。
PS:项目github地址

相关文章

  • Zuul路由网关与过滤器

    技术需求点:1.介绍Zuul网关路由和过滤器两大功能的工作原理;2.模拟Zuul路由网关功能;3.使用Zuul网关...

  • Spring Cloud Zuul网关服务

    内容简介 Zuul网关的功能和工作机制、结合代码介绍如何使用Zuul构建一个简单的网关、介绍Zuul的路由配置方式...

  • SpringCloud 之微服务网关Zuul

    为什么需要使用网关 什么是Zuul Zuul 路由转发 首先创建后台管理服务网关 创建子模块 并加入 依赖 创建 ...

  • Spring Cloud报错之This application

    路由网关(zuul)服务的时候出了This application has no explicit mapping...

  • Zuul 网关路由

    Zuul 网关路由 路由是微服务架构中不可或缺的一部分,例如:/api/user映射到user服务,/api/sh...

  • 路由网关---zuul

    Zuul:Zuul 是在云平台上提供动态路由,监控,弹性,安全等边缘服务的框架。Zuul 相当于是设备和 Netf...

  • 路由网关(zuul)

    在微服务架构中,需要几个基础的服务治理组件,包括服务注册与发现、服务消费、负载均衡、断路器、智能路由、配置管理等,...

  • zuul路由网关

    功能 请求路由和校验过滤 整合 Zuul 和 Eureka 进行整合,将 Zuul 自身注册为 Eureka 服务...

  • 路由网关Zuul

    本章讲解构建微服务的另一个组件——智能网关组件Zuul。Zuul用于构建边界服务,致力于动态路由、过滤、监控、弹性...

  • Zuul:路由网关

    1.1 新建模块 1.2 把consumer-hystrix-dashboard依赖复制 1.3 添加Zuul的依...

网友评论

    本文标题:路由网关Zuul

    本文链接:https://www.haomeiwen.com/subject/fzomxctx.html