关于服务网关Spring Cloud Zuul(Finchley版本)

目录
  • 一、Zuul简介
  • 二、请求路由
    • 2.1传统路由
    • 2.2面向服务的路由
  • 三、路由规则
    • 3.1默认路由规则
    • 3.2自定义路由规则
  • 四、Zuul的过滤器
  • 五、设置熔断
  • 六、实战
    • 6.1pom文件
    • 6.2配置文件
    • 6.3过滤器配置
    • 6.4熔断配置
    • 6.5启动类

一、Zuul简介

Zuul作为微服务系统的网关组件,用于构建边界服务(Edge Service),致力于动态路由、过滤、监控、弹性伸缩和安全。其在微服务架构中有着重要的作用,主要体现在以下六个方面:

Zull、Ribbon以及Eureka相结合可以实现智能路由和负载均衡的功能,Zull可以按照某种策略将请求分发到不同的实例上;

网关作为边界服务,将内部服务的API接口进行聚合并统一对外暴露接口。保护内部服务的API接口,防止内部服务被外界调用泄露敏感信息;

网关可以对用户的身份权限进行认证,防止非法请求API接口;

网关可以实现监控功能,实时日志输出,对请求进行记录;

网关可以用来实现流量监控,在高流量的情况下,对服务进行降级;

API接口从内部服务分离出来,便于测试

二、请求路由

使用Spring Cloud Zuul实现路由的规则是十分简单的。路由方式包括两种:传统路由方式,面向服务的路由方式。

2.1 传统路由

下面我们看以下配置:

zuul.routes.holiday.path=/holiday/**
zuul.routes.holiday.url=http://localhosst:8080/

该规则配置表示所有符合/holiday/** 规则的访问都会被路由转发到http://localhosst:8080/地址上,例如:当我们访问http://localhost:5555/holiday/getAllDays,API网关就会将请求转发到http://localhost:8080/holiday/getAllDays提供的微服务接口上。其中holiday为微服务的名称,可以任意定义,但是一组path和url映射关系的路由名称必须相同,下面面向服务的路由方式也是如此。

2.2 面向服务的路由

Spring Cloud Zuul 与 Spring Cloud Eureka 可以实现无缝对接实现面向服务的路由。我们让路由的path映射到具体的服务上,而具体的url交由Eureka的服务发现机制去自动维护。具体配置如下(其他配置参考下面的实战):

zuul.routes.holiday.path=/holiday/**
zuul.routes.holiday.service-id=holiday

通过上面的配置,我们不需要维护具体实例的位置,是得维护工作十分简单。另外,面向服务打的路由默认实现了负载均衡,而传统路由还需要手动添加所有实例的位置。

三、路由规则

Spring Cloud Zuul提供了默认的路由规则,当然我们也可以修改这个路由规则。

3.1 默认路由规则

Zull与Eureka的配合使用后,Zull会默认配置一个路由规则,这些默认规则的path会使用service-id配置的服务名作为请求的前缀。例如:有holiday服务,他的默认规则如下

zuul.routes.holiday.path=/holiday/**
zuul.routes.holiday.service-id=holiday

由于默认情况下所有Eureka上的服务都会被Zuul自动创建映射关系进行路由,这会使得一些我们不希望对外开放的服务也被外部访问到。这个时候我们可以配置zuul.ignored-services参数来设置一个服务名匹配表达式进行判断,如果服务名匹配表达式,那么Zull将跳过这个服务,不为其创建路由规则。例如:zuul.ignored-services=*表示对所有的服务不自动创建路由规则,这样我们就需要为每个服配置路由规则。

3.2 自定义路由规则

有这样一个场景,由于业务的扩展,版本的升级,服务存在不同的版本。比如我们有这样的命名:holiday-v1、holiday-v2,默认情况下,Zuul自动为服务创建的路由表达式会采用服务名做前缀,针对holiday-v1就会产生/holiday-v1,/holiday-v2两个路径来做映射,但这样生成的表达式规则较为单一,不利于路径规则的管理。

通常,对于上面这种情况,我们希望是生成的路径为/v1/holiday,/v2/holiday。我们可以通过自定义路由规则来实现,具体代码如下:

@Bean
public PatternServiceRouteMapper serviceRouteMapper(){
  return new PatternServiceRouteMapper(
    "(?<name>^.+)-(?<version>v.+$)",
    "${version}/${name}");
}

PatternServiceRouteMapper对象可以让开发者通过正则表达式来自定义服务于路由映射的生成关系。

四、Zuul的过滤器

Zull有请求过滤的功能,其过滤器可以在Http请求的发起和响应返回期间执行一系列的过滤器。

Zuul包扩以下四种过滤器:

  • PRE:该类型的filters在Request routing到源web-service之前执行。可以进行一些权限认证,日志记录,或者额外给Request增加一些属性供后续的filter使用;
  • ROUTING:该类型的filters用于把Request routing到源web-service,源web-service是实现业务逻辑的服务。这里使用HttpClient请求web-service;
  • POST:该类型的filters在ROUTING返回Response后执行。用来实现对Response结果进行修改,收集统计数据以及把Response传输会客户端;
  • ERROR:上面三个过程中任何一个出现错误都交由ERROR类型的filters进行处理。

Zuul过滤器具有以下关键特性:

  • Type(类型):Zuul过滤器的类型,这个类型决定过滤器在哪个阶段执行,例如:pre,post等阶段;
  • Execution Order(执行顺序):规定了过滤器的执行顺序,Order的值越小,越先执行;
  • Criteria(标准):Filters执行所需条件
  • Action(行动):如果符合执行条件,则执行Action(具体逻辑代码)

示例如下:

public class MyFilter extends ZuulFilter {
    @Override
    public Object run() {
            RequestContext ctx = RequestContext.getCurrentContext();
        HttpServletRequest request = ctx.getRequest();
        System.out.println(String.format("%s AccessUserNameFilter request to %s", request.getMethod(), request.getRequestURL().toString()));
        // 获取请求的参数
        String username = request.getParameter("username");
        // 如果请求的参数不为空,且值为chhliu时,则通过
        if(null != username && username.equals("chhliu")) {
          // 对该请求进行路由
            ctx.setSendZuulResponse(true);
            ctx.setResponseStatusCode(200);
            // 设值,让下一个Filter看到上一个Filter的状态
            ctx.set("isSuccess", true);
            return null;
        }else{
          // 过滤该请求,不对其进行路由
            ctx.setSendZuulResponse(false);
            // 返回错误码
            ctx.setResponseStatusCode(401);
            // 返回错误内容
            ctx.setResponseBody("{\"result\":\"username is not correct!\"}");
            ctx.set("isSuccess", false);
            return null;
        }
    }
    @Override
    public boolean shouldFilter() {
    // 是否执行该过滤器,此处为true,说明需要过滤
        return true;
    }
    @Override
    public int filterOrder() {
    // 优先级为0,数字越大,优先级越低
        return 0;
    }
    @Override
    public String filterType() {
    // 前置过滤器
        return "pre";
    }
}

Zuul请求的生命周期如图所示:

五、设置熔断

通常在服务无法提供服务的时候,需要执行熔断。zuul上实现熔断需要实现FallbackProvider的接口。实现接口中的两个方法:getRoute()用于指定应用在哪个服务上;fallbackResponse()进入熔断功能的执行逻辑。示例如下:

@Component
public class CustomZuulFallbackHandler implements FallbackProvider {
  private final Logger logger = LoggerFactory.getLogger(FallbackProvider.class);
  /**
   * 指定处理的service
   *
   * @return
   */
  @Override
  public String getRoute() {
    return "*";
  }
  public ClientHttpResponse fallbackResponse(String route) {
    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((route+" is unavailable.").getBytes());
      }
      @Override
      public HttpHeaders getHeaders() {
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        return headers;
      }
    };
  }
  @Override
  public ClientHttpResponse fallbackResponse(String route, Throwable cause) {
    if (cause != null) {
      String reason = cause.getMessage();
      logger.info("Excption {}",reason);
    }
    return fallbackResponse(route);
  }
}

六、实战

6.1 pom文件

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <groupId>com.southgis.ibase.parent</groupId>
        <artifactId>parentWebService</artifactId>
        <version>2.0.1-SNAPSHOT</version>
        <relativePath>../../parent/parentWebService/pom.xml</relativePath>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <artifactId>api-gateway</artifactId>
    <groupId>com.southgis.ibase.systemassistance</groupId>
    <version>2.0.1-SNAPSHOT</version>
    <packaging>war</packaging>
    <description>网关服务</description>
    <dependencies>
      <!--服务注册与发现-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>
        <!--配置中心-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-config-client</artifactId>
        </dependency>
        <!--路由网关-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.retry</groupId>
            <artifactId>spring-retry</artifactId>
        </dependency>
        <!--cas 客户端-->
        <dependency>
            <groupId>org.jasig.cas.client</groupId>
            <artifactId>cas-client-core</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <build>
        <finalName>apiGateway</finalName>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <mainClass>com.southgis.ibase.systemassistance.ApiGatewayCustomApplication</mainClass>
                </configuration>
                <executions>
                    <execution>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

6.2 配置文件

bootstrap.properties

#服务名 对应配置文件中的{application}部分
spring.application.name=apiGateway
#对应前配置文件中的{profile}部分
spring.cloud.config.profile=dev2
#配置访问路径
server.servlet.context-path=/eureka-server
#注册中心
eureka.client.serviceUrl.defaultZone=http://localhost:8080/eureka-server/eureka
#为监控端点 /info和/health端点也加上类似的前缀
management.server.servlet.context-path=/apiGateway
eureka.instance.statusPageUrlPath=${management.server.servlet.context-path}/actuator/info
eureka.instance.healthCheckUrlPath=${management.server.servlet.context-path}/actuator/health
#通过服务连接配置中心
#spring.cloud.config.discovery.enabled=true
#spring.cloud.config.discovery.serviceId=config-server
spring.cloud.config.uri = http://localhost:8080/config-server
#配置文件获取失败快速返回
spring.cloud.config.failFast=true
#日志配置
#logging.config=classpath:logback-spring.xml
#logging.path=D:/ibase/logs/holiday
#logging.pattern.console=[%d{yyyy-MM-dd HH:mm:ss}] -- [%-5p]: [%c] -- %m%n
#logging.pattern.file=[%d{yyyy-MM-dd HH:mm:ss}] -- [%-5p]: [%c] -- %m%n

apiGateway-dev2.properties

#访问端口
server.port=8080
#设置session超时时间为540分钟
server.servlet.session.timeout=PT540M
#zuul默认为所有服务开启默认的路由,为了服务安全,此处关闭
zuul.ignored-services=*
#代码字典服务路由
zuul.routes.codedict.path=/codedict/**
zuul.routes.codedict.service-id=codedict
#是否转发后还带转发特征的字符
zuul.routes.codedict.strip-prefix=false
#行政区划服务路由
zuul.routes.adminzone.path=/adminzone/**
zuul.routes.adminzone.service-id=adminzone
zuul.routes.adminzone.strip-prefix=false
#是否开启路由重试
zuul.retryable=true
#对当前服务的重试次数
ribbon.MaxAutoRetries=2
#切换实例的重试次数
ribbon.MaxAutoRetriesNextServer=0
#请求处理的超时时间
ribbon.ReadTimeout=6000
#请求连接的超时时间
ribbon.ConnectTimeout=6000
#对所有操作请求都进行重试
ribbon.OkToRetryOnAllOperations=true
#将 hystrix 的超时时间设置成 5000 毫秒(hystrix超时时间小于ribbon连接超时时间,先走hystrix)
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=5000

6.3 过滤器配置

@Configuration
public class ApiGatewayFilter extends ZuulFilter {
  @Override
  public String filterType() {
    return "pre";
  }
  @Override
  public int filterOrder() {
    return 0;
  }
  @Override
  public boolean shouldFilter() {
    return true;
  }
  @Override
  public Object run() throws ZuulException {
    RequestContext context = RequestContext.getCurrentContext();
    HttpServletRequest request = context.getRequest();
    Principal principal = request.getUserPrincipal();
    //获取用户的登录id
    String userId = principal.getName();
    context.addZuulRequestHeader("X-AUTH-ID",userId);
    return null;
  }
}

在这里我们将获取的登录用户id设置到了请求头中传递给内部服务,内部服务可以通过下面的代码进行获取:

String user = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest().getHeader("X-AUTH-ID");

6.4 熔断配置

@Component
public class CustomZuulFallbackHandler implements FallbackProvider {
  private final Logger logger = LoggerFactory.getLogger(FallbackProvider.class);
  /**
   * 指定处理的service
   *
   * @return
   */
  @Override
  public String getRoute() {
    return "*";
  }
  public ClientHttpResponse fallbackResponse(String route) {
    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((route+" is unavailable.").getBytes());
      }
      @Override
      public HttpHeaders getHeaders() {
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        return headers;
      }
    };
  }
  @Override
  public ClientHttpResponse fallbackResponse(String route, Throwable cause) {
    if (cause != null) {
      String reason = cause.getMessage();
      logger.info("Excption {}",reason);
    }
    return fallbackResponse(route);
  }
}

6.5 启动类

**
 * 路由网关服务部署启动类
 *
 * @author simon
 **/
@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
@EnableZuulProxy
@EnableEurekaClient
@SpringCloudApplication
public class ApiGatewayMicroApplication {
  public static void main(String[] args) {
    SpringApplication.run(ApiGatewayMicroApplication.class, args);
  }
}

以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。

(0)

相关推荐

  • Spring Cloud 网关服务 zuul 动态路由的实现方法

    zuul动态路由 网关服务是流量的唯一入口.不能随便停服务.所以动态路由就显得尤为必要. 数据库动态路由基于事件刷新机制热修改zuul的路由属性. DiscoveryClientRouteLocator 可以看到DiscoveryClientRouteLocator 是默认的刷新的核心处理类. //重新加载路由信息方法 protected方法.需要子方法重新方法. protected LinkedHashMap<String, ZuulRoute> locateRoutes() //触发刷新的

  • SpringCloud实战之Zuul网关服务

    为什么需要网关呢? 我们知道我们要进入一个服务本身,很明显我们没有特别好的办法,直接输入IP地址+端口号,我们知道这样的做法很糟糕的,这样的做法大有问题,首先暴露了我们实体机器的IP地址,别人一看你的IP地址就知道服务部署在哪里,让别人很方便的进行攻击操作. 第二,我们这么多服务,我们是不是要挨个调用它呀,我们这里假设做了个权限认证,我们每一个客户访问的都是跑在不同机器上的不同的JVM上的服务程序,我们每一个服务都需要一个服务认证,这样做烦不烦呀,明显是很烦的. 那么我们这时候面临着这两个及其总

  • 详解Spring Cloud Zuul 服务网关

    有了Eureka服务注册发现.Hystrix断路器.Ribbon服务调用负载均衡,以及spring cloud config 集群配置中心,似乎一个微服务框架已五脏俱全,last but not least,一个服务网关却不可或缺. Spring Cloud Zuul路由是微服务架构的不可或缺的一部分,提供动态路由,监控,弹性,安全等的边缘服务.Zuul是Netflix出品的一个基于JVM路由和服务端的负载均衡器. Zuul介绍 在整个Spring Cloud微服务框架里,Zuul扮演着"智能网

  • Spring Cloud 服务网关Zuul的实现

    服务网关的要素 稳定性 安全性 性能,并发性 扩展性 Spring Cloud Zuul - 路由+过滤器 - 核心是一系列的过滤器 Zuul路由配置 management: security: enabled: false // 权限设置 zuul: routes: # myProduct: // 这个名称可以随便填 # path: /myProduct/** # serviceId: product # sensitiveHeader: //敏感头过滤 # 简洁写法 product: /my

  • 关于服务网关Spring Cloud Zuul(Finchley版本)

    目录 一.Zuul简介 二.请求路由 2.1传统路由 2.2面向服务的路由 三.路由规则 3.1默认路由规则 3.2自定义路由规则 四.Zuul的过滤器 五.设置熔断 六.实战 6.1pom文件 6.2配置文件 6.3过滤器配置 6.4熔断配置 6.5启动类 一.Zuul简介 Zuul作为微服务系统的网关组件,用于构建边界服务(Edge Service),致力于动态路由.过滤.监控.弹性伸缩和安全.其在微服务架构中有着重要的作用,主要体现在以下六个方面: Zull.Ribbon以及Eureka相

  • 详解Spring Cloud Zuul网关修改为短连接方法

    目录 一.问题分析 二.解决方式 一.问题分析 之前在用zuul网关的时候,请求几次然后连接就断开了.原因是因为http1.1之后,默认走的都是connection=keep-alive 长连接.但没有心跳维持,顾1分钟断开一次.但RestFul一般都是走短连接就行了.因此想着只要修改头部connection属性就行了. 就是在过滤器中修改Zuul的RequestContext ctx对象 //设置请求为短连接 ctx.addZuulRequestHeader("connection"

  • spring cloud zuul 与 sentinel的结合使用操作

    spring cloud zuul 与 sentinel结合 本来大型服务处理请求超时,限流,降级熔断工作用hystrix,但是这个这个项目不再更新了,虽说它现在提供的版本不会影响到大多数开发者的使用,但是长远考虑,被更换是一件必然的事,而且现在像resilience4j, Sentinel这样的替代品出现,今天我们就看看使用zuul 与 Sentinel整合,实现降级与超时处理,其实网上有很多这样的教程,这里我只是做一个自己的笔记而已 1.必须的依赖 <dependency> <gro

  • spring boot和spring cloud之间的版本关系

    什么是Spring Boot Spring Boot简化了基于Spring的应用开发,通过少量的代码就能创建一个独立的.产品级别的Spring应用. Spring Boot为Spring平台及第三方库提供开箱即用的设置,这样你就可以有条不紊地开始.多数Spring Boot应用只需要很少的Spring配置. Spring Boot是由Pivotal团队提供的全新框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程.该框架使用了特定的方式来进行配置,从而使开发人员不再需要定义样板化的

  • Spring Cloud Zuul路由规则动态更新解析

    这篇文章主要介绍了Spring Cloud Zuul路由规则动态更新解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 背景 Spring Cloud Zuul 作为微服务的网关,请求经过zuul路由到内部的各个service,由于存在着新增/修改/删除服务的路由规则的需求,zuul的路由规则的动态变更功能 提供了 无须重启zuul网关,即可实时更新,现有如下几种方式: 一.基于refresh + config-server事件动态刷新 (1)

  • Spring Cloud Zuul集成Swagger实现过程解析

    Spring Cloud Zuul 集成Swagger 1.准备服务注册中心eureka-server 2.创建微服务swagger-service-a step1. 创建微服务swagger-service-a(Spring Boot项目),添加eureka-client起步依赖,web起步依赖 和swagger依赖 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>s

  • spring cloud zuul增加header传输的操作

    spring cloud zuul增加header传输 在使用OAuth2.0传输权限认证,为了再调用其他的项目的时候获取token,必须在token下传到其他各个服务 @Component public class KeyUserFilter extends ZuulFilter { private static final Logger logger = LoggerFactory.getLogger(KeyUserFilter.class); @Override public Object

  • 利用Spring Cloud Zuul实现动态路由示例代码

    前言 本文主要给大家介绍了关于Spring Cloud Zuul实现动态路由的相关内容,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧. Zuul 是提供动态路由,监控,弹性,安全等的边缘服务.Zuul 相当于是设备和 Netflix 流应用的 Web 网站后端所有请求的前门. Zuul 可以适当的对多个 Amazon Auto Scaling Groups 进行路由请求. 首先新建maven项目,加入如下依赖 <dependencyManagement> <depend

  • 详解Spring Cloud Zuul重试机制探秘

    简介 本文章对应spring cloud的版本为(Dalston.SR4),具体内容如下: 开启Zuul功能 通过源码了解Zuul的一次转发 怎么开启zuul的重试机制 Edgware.RC1版本的优化 开启Zuul的功能 首先如何使用spring cloud zuul完成路由转发的功能,这个问题很简单,只需要进行如下准备工作即可: 注册中心(Eureka Server) zuul(同时也是Eureka Client) 应用服务(同时也是Eureka Client) 我们希望zuul和后端的应用

随机推荐