SpringCloud-Zuul

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/belovehejian/article/details/86437788

什么是 Zuul ?

zuul 是从设备和网站到后端应用程序所有请求的前门,为内部服务提供可配置的对外 URL 到服务的映射关系. 基于 JVM 的后端路由器.其具备一下功能:

  • 认证与鉴权
  • 压力控制
  • 金丝雀测试
  • 动态路由
  • 负载削减
  • 静态响应处理
  • 主动流量管理

其地层是基于 Servlet, 本质组件是一系列的 Filter 所构成的责任链.

示例

创建 Eureka Server 注册中心, Eureka Client (服务提供者工程), Zuul Server 网关中心. 三个工程

Eureka Client 工程:

导入依赖

<dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
    </dependencies>

配置文件:

server:
  port: 8081
spring:
  application:
    name: eureka-clientA
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/

主程序启动类

@SpringBootApplication
@EnableDiscoveryClient
public class EurelaClientAApplication {
    public static void main(String[] args) {
        SpringApplication.run(EurelaClientAApplication.class, args);
    }
}

测试接口:

@RestController
public class TestController {

    @RequestMapping("/add")
    public Integer add(Integer a, Integer b) {
        return a + b;
    }
}

Zuul Server 工程:

依赖:

<dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
    </dependencies>

配置文件:

server:
  port: 8080
spring:
  application:
    name: zuul-server
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/
zuul:
  routes:
    clienta:
      path: /client/**    #凡是 /client 开头的 HTTP 请求, 都会被映射到 clientA 这个服务实例上去, 假设 clientA 的服务实例的端口为 8081
                          # 那么 http://localhost:8080/client/getuser 的请求,在内部会调用映射的地址 http://localhost:8081/getuser 进行服务
                          # 请求, 获取到结果,然后返回
      serviceId: eureka-clientA  #服务实例 ID

主程序启动类:

@SpringBootApplication
@EnableDiscoveryClient
@EnableZuulProxy
public class ZuulServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(ZuulServerApplication.class, args);
    }
}

然后依次启动 Eureka Server, Eureka Client, Zuul Server 三个工程, 然后先直接访问以下接口: http://localhost:8081/add?a=10&b=20 可以看到输出, 说明服务能正常访问:

然后通过 zuul 去访问服务: http://localhost:8080/client/add?a=10&b=20 可以看到以下输出, 说明通过 zuul 能正确访问服务:

当我们调用 http://localhost:8080/client/add?a=10&b=20 地址的时候, 实际上在内部调用的时候调用的是: http://localhost:8081/add?a=10&b=20 , 这是因为我们在 zuul 中配置了路由规则, 当向 zuul 发起请求的时候, 它会去 Eureka 注册中心拉取服务列表, 如果发现有指定的路由规则, 就会按照规则路由到相应的服务接口上去.

zuul 路由配置:

单实例 ServiceId 映射: 上例中我们使用了 

zuul:
  routes:
    clienta:
      path: /client/**    #凡是 /client 开头的 HTTP 请求, 都会被映射到 clientA 这个服务实例上去, 假设 clientA 的服务实例的端口为 8081
                          # 那么 http://localhost:8080/client/getuser 的请求,在内部会调用映射的地址 http://localhost:8081/getuser 进行服务
                          # 请求, 获取到结果,然后返回
      serviceId: eureka-clientA  #服务实例 ID

其实这个写法可以简化成这样 (第一种写法)

zuul:
  routes:
    eureka-clientA: /client/**

还可以简化成这样, 映射规则与 ServiceId 都不用写 (第二种写法):

zuul:
  routes:
    eureka-clientA:

在这种情况下,  Zuul 会为  eureka-clientA 添加一个默认的映射规则 /client-clienta/** , 也就是相当于 下面这样写

zuul:
  routes:
    eureka-clientA:
      path: /eureka-clienta/**
      serviceId: eureka-clientA

单实例 url 映射

除了路由到服务之外, 还可以路由到具体的地址, 只需要将 serviceId 替换成 url 就可以了.如下所示:

#映射到具体的url
zuul:
  routes:
    eureka-clientA:
      path: /client/**
      url: http://localhost:8081  # eureka-clientA 所在的地址

多实例路由

在默认情况下 Zuul 会使用 Eureka 中集成的负载均衡功能, 如果想要使用 Ribbon 的辅助均衡功能, 就需要指定一个 serviceId, 此操作需要禁止 Ribbon 使用 Eureka. 在 E 版之后,新增了负载均衡策略的配置,如下

zuul:
  routes:
    eureka-clientA:
      path: /client/**
      serviceId: eureka-clientA #服务实例ID
ribbon:
  eureka:
    enabled: false #禁止 ribbon 使用eureka

#为服务实例ID 配置 负载均衡策略
eureka-clientA:
  ribbon:
    NIWSServerListClassName: com.netflix.loadbalancer.ConfigurationBasedServerList  #用于获取服务实例列表的类
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule  #负载均衡策略
    listOfServers: localhost:8081, localhost:8082, localhost:8083 # 所有可用的服务提供者的服务实例地址,

然后在 eureka-clientA 服务提供者个工程的对外接口中增加一个方法, 

@RequestMapping("/gethost")
    public String getHostAndPort(HttpServletRequest request) {
        return String.valueOf(request.getServerPort()); //获取端口
    }

然后依次eureka 注册中心, 并且以不同的端口启动 eureka-clientA 服务的3 个实例, 然后在启动 zuul , 然后在浏览器访问:http://localhost:8080/client/gethost 可以看到

这几个端口随机出现, 说明使用了我们定义好的 随机策略. 至于为什么要 Ribbon 禁用 Eureka , 这个还在研究当中

forward 本地跳转

有时候我们在 zuul 中做一些逻辑处理, 我们希望在访问 /client 接口的时候转到指定的方法上来处理, 就需要用到 zuul 的本地跳转,如:

修改 zuul 配置文件

# zuul 配置本地转发, 当请求/client 开头的接口时, 会被 API网关转到到 API 网关中以 /client 为前缀的请求上
# 假如: 当API 网关接收到 /client/add 之类的请求的时候, 因为符合规则, 所以请求会被 API 网关转发到网关的
# /client/add 上.
zuul:
  routes:
    eureka-clientA:
      path: /client/**    #当符合该路由规则的请求到达时, 会被 API网关转到到 API 网关中以 /client 为前缀的请求上
                          # 个人理解是, 本地转发的时候, 会用 本地转发指定的前缀, 替换掉 路由匹配的前缀, 然后把后面的地址
                          #在拼接起来, 如, 请求 http://localhost:8080/client/a/b/c/getuser ,因为符合路由规则, 所以会转发到
                          # zuul 中的 http://localhost:8080/user/a/b/c/getuser.
      url: forward:/user

在 zuul 中新增一个对外接口类, 根据上面的描述 接口的地址必须为: /user/add 否则会报 404 错误

@RestController
public class TestControlelr {

    @RequestMapping("/user/add")
    public String add(Integer a, Integer b) {
        return "本地跳转" + (a + b);
    }
}

启动服务, 然后访问 http://localhost:8080/client/add?a=10&b=20 可以看到输出, 说明本地跳转成了, 

如果将 zuul 网关中的接口地址改成了 /user, 然后在访问接口, 这个时候本地转发就会错误了. 

所以要按照规则处理.

如果有这样一种配置:

zuul:
  routes:
    eureka-clientA:
      path: /client/**
      serviceId: eureka-clientA
    eureka-clientB:
      path: /client/**
      serviceId: eureka-clientB

路由规则是一样的, 经过测试, 它总是会匹配到配置文件后面的那个服务上去. 这里是 eureka-clientB 服务上.yml解释器在 工作的时候, 如果同一个映射对应多个服务, 按照加载顺序, 最末尾加载的映射会覆盖前面加载的映射.

zuul 还可以配置路由前缀, 服务屏蔽, 路径屏蔽, 敏感头信息(也就是切换敏感信息与下游服务器的交互),配置重定向(比如隐藏真实服务的 IP, 暴露zuul 网关的IP), 重试机制等. 

参考<重新定义 Spring Cloud> 一书

猜你喜欢

转载自blog.csdn.net/belovehejian/article/details/86437788