Spring Cloud学习:04路由网关(Zuul)

1 Zuul介绍

通过前几个核心组件,可以构建一个简略(不完善)的微服务架构:

在该架构中,我们的服务集群包含:内部服务Service A和Service B,他们都会注册与订阅服务至Eureka Server,而Open Service是一个对外的服务,通过均衡负载公开至服务调用方。

当前架构存在的不足:

首先,破坏了服务无状态特点。为了保证对外服务的安全性,我们需要实现对服务访问的权限控制,而开放服务的权限控制机制将会贯穿并污染整个开放服务的业务逻辑,这会带来的最直接问题是,破坏了服务集群中REST API无状态的特点。从具体开发和测试的角度来说,在工作中除了要考虑实际的业务逻辑之外,还需要额外可续对接口访问的控制处理。 其次,无法直接复用既有接口。当我们需要对一个即有的集群内访问接口,实现外部服务访问时,我们不得不通过在原有接口上增加校验逻辑,或增加一个代理调用来实现权限控制,无法直接复用原有的接口。

解决思路:

需要将权限控制这样的东西从我们的服务单元中抽离出去,而最适合这些逻辑的地方就是处于对外访问最前端的地方,我们需要一个更强大一些的均衡负载器,也就是服务网关。

服务网关是微服务架构中一个不可或缺的部分。通过服务网关统一向外系统提供REST API的过程中,除了具备服务路由、均衡负载功能之外,它还具备了权限控制等功能。Spring Cloud Netflix中的Zuul就担任了这样的一个角色,为微服务架构提供了前门保护的作用,同时将权限控制这些较重的非业务逻辑内容迁移到服务路由层面,使得服务集群主体能够具备更高的可复用性和可测试性。

2 Zuul路由测试

2.1 基于之前工程,创建新模块zuul-service,选择Spring Initializr->Cloud Discovery->Eureka Discovery,并添加以下依赖:

<dependencies>
   <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-eureka</artifactId>
   </dependency>
   <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-test</artifactId>
      <scope>test</scope>
   </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>
</dependencies>

2.2 启动类上添加@EnableZuulProxy开启Zuul功能

@SpringBootApplication
@EnableZuulProxy
public class ZuulServiceApplication {

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

2.3 配置文件添加相关配置

server:
    port: 8769

eureka:
    client:
      serviceUrl:
        defaultZone: http://localhost:8761/eureka/

spring:
    application:
      name: zuul-service #指明应用名称(服务与服务相互调用根据name属性)

zuul:
  routes:
    api-a:
      path: /api-ribbon-service/**
      serviceId: ribbon-service
    api-b:
      path: /api-feign-service/**
      serviceId: feign-service

配置服务端口为8769,应用名称为 zuul-service;配置以/api-ribbon-service/开头的请求转发到ribbion-service服务,以/api-feign-service/开头的请求转发到feign-service服务。

2.4 依次启动服务注册中心、one-service、ribbon-service、feign-service、zuul-service

浏览器请求 http://localhost:8769/api-ribbon-service/one 结果:

浏览器请求http://localhost:8769/api-feign-service/one 结果:

说明zuul起到了路由功能。

3 Zuul服务过滤测试

添加自定义的授权过滤器,继承ZuulFilter

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

    @Override
    public String filterType() {
        return "pre";
    }

    @Override
    public int filterOrder() {
        return 0;
    }

    @Override
    public boolean shouldFilter() {
        return true;
    }

    @Override
    public Object run() {
        RequestContext context = RequestContext.getCurrentContext();
        HttpServletRequest request = context.getRequest();
        LOGGER.info("{}--->{}", request.getMethod(), request.getRequestURL().toString());
        Object token = request.getParameter("token");
        if (token == null) {
            LOGGER.info("token is empty");
            context.setSendZuulResponse(false);
            context.setResponseStatusCode(401);
            try {
                context.getResponse().getWriter().write("token is empty");
            } catch (Exception e) {

            }
            return null;
        }
        LOGGER.info("ok");
        return null;
    }
}

① filterType定义:

PRE&nbsp;路由前 ROUTING&nbsp;路由中 POST&nbsp;路由后 ERROR&nbsp;发生错误调用

Zuul Request Lifecycle

② filterOrder:过滤顺序

③ shouldFilter:是否需要过滤,返回boolean值

④ run:过滤逻辑

浏览器访问 http://localhost:8769/api-feign-service/one 结果:

添加token参数请求 http://localhost:8769/api-feign-service/one?token=haha 结果:

本文源码下载地址:

https://github.com/laravelshao/spring-cloud-learning/tree/master/setion04-zuul

4 参考资料

翟永超->Spring Cloud构建微服务架构:服务网关(基础)

Spring->Router and Filter: Zuul

GitHub->Netflix Zuul Filter

方志朋->史上最简单的SpringCloud教程

&nbsp;

文章来源:

Author:LaravelShao
link:https://my.oschina.net/LaravelShao/blog/1563405