基于Spring Cloud Zuul搭建网关服务

1. 网关服务所谓何

  在微服务架构风格中,一个大应用被拆分成为了多个小的服务系统提供出来,这些小的系统他们可以自成体系,也就是说这些小系统可以拥有自己的数据库,框架甚至语言等,这些小系统通常以提供 RestFul 风格的接口来被 H5, Android, IOS 以及第三方应用程序调用。

  但是在UI上进行展示的时候,我们通常需要在一个界面上展示很多数据,这些数据可能来自于不同的微服务中。如果想通过一个统一的入口来请求不同的服务,那么给应用专门建立一个网关(Gateway)服务就显得非常有必要了。下图展示了一个拥有网关服务的微服务架构设计。
一个简单的微服务架构设计图
  微服务中的网关服务同其他服务一样,被微服务的注册中心统一发现并管理,网关服务一般负责处理负载均衡、缓存、路由、访问控制、服务代理、监控、日志等。本文主要实现网关服务的路由转发和过滤功能。

2. Zuul来过滤且分发

2.1 NetFlix Zuul

Zuul is the front door for all requests from devices and websites to the backend of the Netflix streaming application. As an edge service application, Zuul is built to enable dynamic routing, monitoring, resiliency, and security.

  以上内容摘自NetFlix Zuul官方Git Wiki。这段话高度概括了Zuul的作用,大概意思是Zuul是所有从客户端发往服务端的请求的“守门人”,可以提供动态路由、监控、弹性、安全等边缘服务。

Zuul uses a range of different types of filters that enables us to quickly and nimbly apply functionality to our edge service. These filters help us perform the following functions:

  • Authentication and Security - identifying authentication requirements for each resource and rejecting requests that do not satisfy them.
  • Insights and Monitoring - tracking meaningful data and statistics at the edge in order to give us an accurate view of production.
  • Dynamic Routing - dynamically routing requests to different backend clusters as needed.
  • Stress Testing - gradually increasing the traffic to a cluster in order to gauge performance.
  • Load Shedding - allocating capacity for each type of request and dropping requests that go over the limit.
  • Static Response handling - building some responses directly at the edge instead of forwarding them to an internal cluster
  • Multiregion Resiliency - routing requests across AWS regions in order to diversify our ELB usage and move our edge closer to our members

2.2 Spring Cloud Zuul

Spring Cloud has created an embedded Zuul proxy to ease the development of a common use case where a UI application wants to make proxy calls to one or more back end services. This feature is useful for a user interface to proxy to the back end services it requires, avoiding the need to manage CORS and authentication concerns independently for all the back ends.

  以上内容摘自Spring Cloud官方文档。大致意思是Spring Cloud内嵌了Zuul以适应一个代理调用多个不同后端服务的通用场景,使得在开发过程中不用关心跨域资源共享和安全认证等细节。

3. 实际动手初体验

3.1 搭建Eureka微服务框架

  内嵌在Spring Cloud中的Zuul Proxy需要依赖Eureka的服务发现功能,所以万里长征第一步是搭建Spring Eureka微服务框架。

  1. 新建项目(即project)demo-parent,在它下面新建模块(即module)demo-eureka-server作为服务注册中心、demo-gateway作为网关服务、demo-web作为一个普通服务。
    在这里插入图片描述
  2. 将demo-eureka-server设置为注册中心,并把demo-gateway和demo-web注册到demo-eureka-server上面。
  • 在demo-eureka-server的pom文件中添加依赖
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
  • 在demo-eureka-server启动类DemoEurekaServerApplication前面添加@EnableEurekaServer注解表明这个模块是Eureka服务注册中心
  • 在demo-eureka-server的application.yml文件中添加配置
server:
  port: 8761

eureka:
  instance:
    hostname: localhost
  client:
    fetch-registry: false
    register-with-eureka: false
    service-url:
      default-zone: http://${eureka.instance.hostname}:${server.port}/eureka/

spring:
  application:
    name: demo-eureka-server
  • 在demo-gateway和demo-web的pom文件中添加依赖
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
  • 在demo-gateway和demo-web启动类前面添加@EnableEurekaClient注解表明这个模块可以被注册中心发现
  • 在demo-gateway的application.yml文件中添加配置
server:
  port: 8767

eureka:
  client:
    service-url:
      default-zone: http://localhost:8761/eureka/

spring:
  application:
    name: demo-gateway
  • 在demo-web的application.yml文件中添加与demo-gateway类似的配置,不过要注意区分端口号,设置demo-web的端口号为8768
  • 此时,分别运行三个模块的启动类,可以看到demo-gateway和demo-web已经被注册到了demo-eureka-server上面
    在这里插入图片描述

3.2 配置Gateway服务

  1. 将demo-gateway设置为网关服务,能够将请求进行过滤并且分发到不同的服务上
  • 在demo-gateway的pom文件中添加依赖
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
  • 在demo-gateway启动类上面添加@EnableZuulProxy注解表明这个模块是网关服务模块
  • 在demo-gateway的application.yml文件中添加配置
zuul:
  routes:
    web:
      path: /web/**
      serviceId: demo-web

  这里采用了手动映射路由的方式,意思是当请求路径包含“/web”的时候,当前请求会被转发到demo-web服务上。如果不想手动映射,可以在pom文件引入spring-boot-starter-actuator依赖,再在application.yml添加端点暴露的有关配置(这里不再详细说明),浏览器访问http://localhost:8767/actuator/routes就可以看到demo-gateway配置的各服务路径映射关系。"/web/**":"demo-web"是我们手动配置的映射关系,"/demo-web/**":"demo-web"是自动配置的映射关系,也就是说http://localhost:8767/web/hi和http://localhost:8767/demo-web/hi都会去请求demo-web服务上的hi方法。
在这里插入图片描述
2. 实现demo-gateway的过滤功能
  目前demo-gateway已经具备了分发路由的功能,如果想在请求方法之前进行一些验证,需要继承ZuulFilter类并重写有关方法。

@Component
public class CommonAccessPreFilter extends ZuulFilter {

    private static Logger logger = LoggerFactory.getLogger(CommonAccessPreFilter.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() throws ZuulException {
        RequestContext ctx = RequestContext.getCurrentContext();
        HttpServletRequest request = ctx.getRequest();
        logger.info(String.format("%s >>> %s", request.getMethod(), request.getRequestURL().toString()));
        String id = request.getParameter("id");
        if (id == null)
            logger.warn("id is null");
        else
            logger.info("id = " + id);
        return null;
    }
}

  filterType方法定义过滤器的类型。Zuul中定义了四种不同类型的过滤器,分别是pre(在请求被路由之前调用)、route(在请求路由时调用)、error(处理请求时发生错误时被调用)、post(在route和error之后被调用)。本文使用pre过滤器,即在路由之前做一些验证。
  filterOrder方法定义过滤器的执行顺序,数值越大,优先级越低。
  shouldFilter方法是过滤器的开关,返回true时过滤器才会生效。
  run方法里面是具体的过滤逻辑。本文举例验证请求参数id是否为空,针对id是否为null可以个性化定制不同的逻辑。
  下图是分别请求http://localhost:8767/web/hi?id=1和http://localhost:8767/web/hi时过滤器打印在控制台的日志。
在这里插入图片描述在这里插入图片描述

4. 脚下足迹永留存

  完整项目源码已上传至个人公开GitHub仓库

发布了9 篇原创文章 · 获赞 20 · 访问量 13万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章