天天看点

Spring Cloud Netflix Zuul 服务网关

文章目录

    • 1 概述
    • 2 准备工作
      • 2.1 服务注册
      • 2.2 服务消费
    • 3 基本使用
    • 4 请求过滤
    • 5 其他配置
      • 5.1 匹配规则
      • 5.2 忽略路径
      • 5.3 前缀

学习在 Spring Cloud 中使用 Zuul 实现服务网关,包括基本使用、请求过滤、忽略路径、前缀等功能。它是 Netflix 家族成员之一。

1 概述

由于每一个微服务的地址都有可能发生变化,无法直接对外公布这些服务地址,基于安全以及高内聚低耦合等设计,我们有必要将内部系统和外部系统做一个切割。

一个专门用来处理外部请求的组件,就是服务网关,常用功能:

  • 权限问题统一处理
  • 数据剪裁和聚合
  • 简化客户端的调用
  • 可以针对不同的客户端提供不同的网关支持

在 Spring Cloud 中,网关主要有两种实现方案:

Zuul

Spring Cloud Gateway

Zuul 是 Netflix 公司提供的网关服务,主要有如下功能:

  • 权限控制,可以做认证和授权
  • 监控
  • 动态路由
  • 负载均衡
  • 静态资源处理

Zuul 中的功能基本上都是基于过滤器来实现,它的过滤器有几种不同的类型:

  • PRE
  • ROUTING
  • POST
  • ERROR

2 准备工作

2.1 服务注册

创建 Spring Boot 项目

zuul-client-provider

,作为我们的服务提供者,添加

Web/Eureka Client

依赖,如下:

Spring Cloud Netflix Zuul 服务网关

最终的依赖如下:

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

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
        <exclusions>
            <exclusion>
                <groupId>org.junit.vintage</groupId>
                <artifactId>junit-vintage-engine</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
</dependencies>
           

项目创建成功后,修改

application.properties

配置文件,将 zuul-client-provider 注册到 Eureka Server 上(服务注册中心使用 Eureka Server ),如下:

# 当前服务的名称
spring.application.name=zuul-client-provider
# 当前服务的端口
server.port=6000

# 服务注册中心地址
eureka.client.service-url.defaultZone=http://127.0.0.1:1111/eureka
           

接下来,启动 Eureka Server ,待服务注册中心启动成功后,再启动 zuul-client-provider ,两者都启动成功后,访问 http://127.0.0.1:1111 可以看到 zuul-client-provider 的注册信息。

当然 zuul-client-provider 也可以集群化部署,下面对 zuul-client-provider 进行打包,之后我们在命令行启动两个 provider 实例:

java -jar zuul-client-provider-0.0.1-SNAPSHOT.jar --server.port=6000
java -jar zuul-client-provider-0.0.1-SNAPSHOT.jar --server.port=6001
           

最后在 zuul-client-provider 提供一个 hello 接口,用于后续服务消费者 zuul-client-consumer 来消费,如下:

@RestController
public class ProviderController {
    @Value("${server.port}")
    Integer port; // 支持启动多个实例,做负载均衡,用端口区分

    @GetMapping("/hello")
    public String hello() {
        return "hello cxy35: " + port;
    }
}
           

2.2 服务消费

创建 Spring Boot 项目

zuul-client-consumer

,作为我们的服务消费者,添加

Web/Eureka Client/Zuul

依赖,如下:

Spring Cloud Netflix Zuul 服务网关

最终的依赖如下:

<dependencies>
  <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
  </dependency>
  <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-netflix-eureka-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-test</artifactId>
      <scope>test</scope>
      <exclusions>
          <exclusion>
              <groupId>org.junit.vintage</groupId>
              <artifactId>junit-vintage-engine</artifactId>
          </exclusion>
      </exclusions>
  </dependency>
</dependencies>
           

项目创建成功后,修改

application.properties

配置文件,将 zuul-client-consumer 注册到 Eureka Server 上(服务注册中心使用 Eureka Server ),如下:

# 当前服务的名称
spring.application.name=zuul-client-consumer
# 当前服务的端口
server.port=6002

# 服务注册中心地址
eureka.client.service-url.defaultZone=http://127.0.0.1:1111/eureka
           

接着,在项目启动类上添加

@EnableZuulProxy

注解,开启网关代理,如下:

@SpringBootApplication
@EnableZuulProxy // 开启网关代理
public class ZuulClientConsumerApplication {

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

}
           

接下来,启动 zuul-client-consumer ,访问 http://127.0.0.1:1111 可以看到 zuul-client-consumer 的注册信息。

3 基本使用

配置完成后,访问 http://127.0.0.1:6002/zuul-client-provider/hello ,会自动通过 Zuul 的代理访问到 zuul-client-provider 中对应的的接口,无需知道其真实的地址。在这个访问地址中, zuul-client-provider 就是要访问的服务名称, /hello 则是要访问的服务接口。

当然, Zuul 中的路由规则也可以自己配置,如下:

# Zuul 中的路由规则配置
# zuul.routes.cxy35.path=/cxy35/**
# zuul.routes.cxy35.service-id=zuul-client-provider

# 简化配置
zuul.routes.zuul-client-provider=/cxy35/**
           

上面配置表示满足

/cxy35/**

这个匹配规则的请求,将被转发到 zuul-client-provider 实例上。比如:http://127.0.0.1:6002/cxy35/hello

4 请求过滤

对于来自客户端的请求,可以在 Zuul 中进行预处理,例如权限判断等。

zuul-client-consumer

中定义一个简单的权限过滤器,如下:

@Component
public class PermissionFilter extends ZuulFilter {
    /**
     * 过滤器类型,权限判断一般是 pre
     *
     * @return
     */
    @Override
    public String filterType() {
        return "pre";
    }

    /**
     * 过滤器优先级
     *
     * @return
     */
    @Override
    public int filterOrder() {
        return 0;
    }

    /**
     * 是否过滤
     *
     * @return
     */


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

    /**
     * 核心的过滤逻辑写在这里
     *
     * @return 这个方法虽然有返回值,但是这个返回值目前无所谓
     * @throws ZuulException
     */
    @Override
    public Object run() throws ZuulException {
        RequestContext ctx = RequestContext.getCurrentContext();
        HttpServletRequest request = ctx.getRequest();//获取当前请求
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        if (!"cxy35".equals(username) || !"123456".equals(password)) {
            //如果请求条件不满足的话,直接从这里给出响应
            ctx.setSendZuulResponse(false);
            ctx.setResponseStatusCode(401);
            ctx.addZuulResponseHeader("content-type", "text/html;charset=utf-8");
            ctx.setResponseBody("非法访问,无权限");
        }
        return null;
    }
}
           

重启 zuul-client-consumer ,接下来,发送请求必须带上 username 和 password 参数,否则请求不通过,比如:http://127.0.0.1:6002/cxy35/hello?username=cxy35&password=123456

5 其他配置

5.1 匹配规则

例如有两个服务,一个叫 provider ,另一个叫 provider-hello ,在做路由规则设置时,假如出现了如下配置:

zuul.routes.provider=/provider/**

zuul.routes.provider-hello=/provider/hello/**
           

此时,如果访问一个地址:

http://127.0.0.1:6002/provider/hello/123

,会出现冲突。实际上,这个地址是希望和 provider-hello 这个服务匹配的,这个时候,只需要把配置文件改为 yml 格式就可以了,因为 yml 格式的配置是有序的。

5.2 忽略路径

默认情况下,Zuul 注册到 Eureka 上之后, Eureka 上的所有注册服务都会被自动代理。如果不想给某一个服务做代理,可以忽略该服务,配置如下:

zuul.ignored-services=provider2
           

上面这个配置表示忽略 provider2 服务,此时就不会自动代理 provider2 服务了。

当然,也可以忽略某一类地址,配置如下:

zuul.ignored-patterns=/**/hello/**
           

这个表示请求路径中如果包含 hello ,则不做代理。

5.3 前缀

可以统一给路由加前缀,配置如下:

zuul.prefix=/cxy35
           

这样,以后所有的请求地址自动多了前缀

/cxy35

  • Spring Cloud 教程合集(微信左下方阅读全文可直达)。
  • Spring Cloud 教程合集示例代码:https://github.com/cxy35/spring-cloud-samples
  • 本文示例代码:https://github.com/cxy35/spring-cloud-samples/tree/master/spring-cloud-zuul

扫码关注微信公众号 程序员35 ,获取最新技术干货,畅聊 #程序员的35,35的程序员# 。独立站点:https://cxy35.com

Spring Cloud Netflix Zuul 服务网关

继续阅读