Spring Cloud框架学习-Spring Cloud Zuul

1. 基本介绍

由于每一个微服务的地址都有可能发生变化,无法直接对外公布这些服务地址,基于安全以及高内聚低耦合等设计,我们有必要将内部系统和外部系统做一个切割。需要一个专门用来处理外部请求的组件,就是服务网关。API网关的的定义类似于面向对象设计模式中的Facade模式,像是整个微服务架构系统的门面一样,所有的外部客户端访问都需要经过它来调度和过滤。API网关需要实现请求路由,负载均衡,校验过滤,请求转发时的熔断机制,服务的聚合等功能。

Spring Cloud 中,API网关主要有两种实现方案:Zuul和Spring Cloud Gateway。Spring Cloud Zuul是基于Neflix Zuul实现的API网关组件。Zuul 具备的功能:

  • 作为系统的统一入口,屏蔽系统内部各个微服务的细节
  • 实现接口权限校验
  • 监控
  • 动态路由
  • 负载均衡
  • 静态资源处理

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

  • pre:可以在请求被路由之前调用
  • routing:在路由请求时被调用
  • post:在routing和error过滤器之后被调用
  • error:处理请求时发送错误时被调用

2. 使用示例

2.1 基本使用

沿用之前文章所创建的Eureka服务和Provider服务。Spring Cloud框架学习-注册中心Spring Cloud Eureka

新创建名为Zuul的Spring Boot项目,使用Spring Boot版本2.2.4,pom.xml添加如下依赖:

<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.6.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>


    <groupId>top.javahai.spring.cloud</groupId>
    <artifactId>zuul</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>zuul</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>1.8</java.version>
        <spring-cloud.version>Hoxton.SR6</spring-cloud.version>
    </properties>
    <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>
        </dependency>
    </dependencies>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

在启动类上添加注解@EnableZuulProxy开启Zuul的API网关代理:

@SpringBootApplication
@EnableZuulProxy
public class ZuulApplication {
    
    

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

在application.properties中配置当前Zuul服务的基础信息

#服务名
spring.application.name=zuul
#服务端口号
server.port=2020
#注册中心url地址
eureka.client.service-url.defaultZone=http://localhost:1111/eureka

启动注册中心,provider服务和zuul服务,在注册中心管理界面查看服务是否启动成功
在这里插入图片描述
然后请求地址:http://localhost:2020/v1/provider/hello,通过Zuul的代理可以访问到provider服务。
在这里插入图片描述

2.2 路由转发配置

在application.properties中配置路由规则

zuul.routes.provider.path=/provider-test/**
zuul.routes.provider.service-id=provider

通过上面的配置定义了满足/provider-test/**这个匹配规则的请求,将会转发到provider服务上处理。
在这里插入图片描述

上面配置路由规则的两行配置还可以简化成一行配置

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

通过以下配置可以实现满足规则的请求路由转发到具体的URL上。其中api-test-url为路由名,一组path和url映射关系的路由名必须相同

zuul.routes.api-test-url.path=/api-test/**
zuul.routes.api-test-url.url=http://localhost:8080/

2.3 请求过滤配置

每个客户端用户请求微服务应用提供的接口时,它们的访问权限往往都有一定的限制,系统不会将所有的微服务接口都对它们开放。这就需要要网关中统一实现请求的权限校验。在Zuul中我们只需要继承ZuulFilter抽象类并实现它定义的4个抽象方法就可以完成对请求的拦截和过滤了。

下面实现一个简单的Zuul过滤器,实现在请求过滤之前检查HttpServletRequest中是否有username和password参数且是否满足要求。如满足则进行路由,否则就拒绝访问,返回401错误。

//注册到Spring容器中
@Component
public class PermissionFilter extends ZuulFilter {
    
    
    /**
     * 过滤器类型,它决定过滤器在请求的哪个生命周期中执行。
     * 权限判断一般是pre,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 (!"admin".equals(username) || !"123".equals(password)) {
    
    
            //设置不进行路由
            ctx.setSendZuulResponse(false);
            ctx.setResponseStatusCode(401);
            ctx.addZuulResponseHeader("content-type","text/html;charset=utf-8");
            ctx.setResponseBody("非法访问");
        }
        return null;
    }
}

重启Zuul接下来发送请求就必须带上username 和 password 参数,否则请求不通过。
在这里插入图片描述
带上username 和 password 参数发送请求
在这里插入图片描述

3. 更多配置

3.1 忽略路径

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

zuul.ignored-services=provider

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

忽略某一类地址:

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

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

3.2 设置路由前缀

我们可以通过zuul.prefix参数全局地为路由规则增加前缀信息,给路由添加前缀的配置示例:

zuul.prefix=/v1

这样所有的请求地址都需要添加前缀/v1
在这里插入图片描述

3.3 路径匹配规则

路径匹配的表达式采用了Ant风格定义,Ant风格的路径表达式一共有三种通配符。分别是:

通配符 说明
匹配任意单个字符
* 匹配任意数量的字符,不支持多级目录(例如/user-service/*无法匹配/user-service/a/b)
** 匹配任意数量的字符,支持多级目录

3.4 Hystrix和Ribbon配置

#设置API网关中路由转发请求的hystrixCommand执行超时时间,单位为毫秒
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=
#设置路由转发请求的时候,创建请求连接的超时时间
ribbon.ConnectTimeOut=
#设置路由转发请求的超时时间
ribbon.ReadTimeout=

参考:
1.《Spring Cloud微服务实战》

猜你喜欢

转载自blog.csdn.net/huangjhai/article/details/127154505