欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

6.使用zuul实现网关

程序员文章站 2024-03-21 15:36:40
...

前面的文章我们介绍了,Eureka用于服务的注册于发现,Feign支持服务的调用以及均衡负载,Hystrix处理服务的熔断防止故障扩散,Spring Cloud Config服务集群配置中心,似乎一个微服务框架已经完成了。

我们还是少考虑了一个问题,外部的应用如何来访问内部各种各样的微服务呢?在微服务架构中,后端服务往往不直接开放给调用端,而是通过一个API网关根据请求的url,路由到相应的服务。当添加API网关后,在第三方调用端和服务提供方之间就创建了一面墙,这面墙直接与调用方通信进行权限控制,后将请求均衡分发给后台服务端。

zuul的简单使用

首先创建一个springboot项目,在pom文件中增加以下依赖:

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

在application.properties文件中增加以下配置:

spring.application.name=springcloud-zuul
server.port=8888

# 访问/mycsdn/** 会被重定向到https://blog.csdn.net/**
zuul.routes.baidu.path=/mycsdn/**
zuul.routes.baidu.url=https://blog.csdn.net/

在启动类上添加@EnableZuulProxy注解,如下:

@EnableZuulProxy
@SpringBootApplication
public class SpringcloudZuulApplication {

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

}

然后,启动项目,在浏览器中访问:http://localhost:8888/mycsdn/qq_37584164,可以看到页面自动跳转到了我的csdn博客的主页:
6.使用zuul实现网关

服务路由

通过服务路由的功能,我们在对外提供服务的时候,只需要通过暴露Zuul中配置的调用地址就可以让调用方统一的来访问我们的服务,而不需要了解具体提供服务的主机信息了。

在Zuul中为我们提供了两种路由的映射方式:

  • 通过URL直接映射,也就是上面的例子中使用的那种方式,在application.properties文件中配置形式如下:

    # routes to url
    zuul.routes.api-a-url.path=/api-a-url/**
    zuul.routes.api-a-url.url=http://localhost:2222/
    

    通过该配置,Zuul中所有规则为/api-url/**的访问都会被映射到http://localhost:2222/**,比如当我们访问http://localhost:8888/api-url/add?id=1&name=zhangsan时,Zuul会将该请求路由到http://localhost:2222/add?id=1&name=zhangsan上。

    上面的配置中的zuul.routes.api-a-url.path,其中api-a-url是路由的名字,可以根据需要任意定义,但是同一组映射的path和URL的这部分要一样。

  • 通过url映射的方式对于Zuul来说,并不是特别友好,Zuul需要知道我们所有为服务的地址,才能完成所有的映射配置。而实际上,我们在实现微服务架构时,服务名与服务实例地址的关系在eureka server中已经存在了,所以只需要将Zuul注册到eureka server上去发现其他服务,我们就可以实现对serviceId的映射。

    采用这种映射方式,就需要将Zuul也注册到Eureka注册中心中,所以需要在pom中增加依赖:

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

    然后,修改application.properties文件为如下:

    zuul.routes.api-a.path=/provider/**
    zuul.routes.api-a.serviceId=service-provider
    eureka.client.serviceUrl.defaultZone=http://localhost:8000/eureka/
    

    这里需要使用到之前的service-provider项目,作为服务提供者来进行演示。可以看到这里的配置跟直接通过URL映射配置不同之处就是将url改成了serviceId。

    修改启动类,增加@SpringCloudApplication注解,如下:

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

    注意这里用的是@SpringCloudApplication注解,之前没有提过,通过源码我们看到,它整合了@SpringBootApplication@EnableDiscoveryClient@EnableCircuitBreaker,主要目的还是简化配置。

    最后,我们依次启动Eureka、service-provider、Zuul,启动成功后在注册中心页面可以看到启动的所有服务了。

    在浏览器中访问:http://localhost:8888/provider/service-provider/index,这就等同于访问:http://localhost:9001/service-provider/index,相当于使用“http://localhost:8888/provider/”代替了真实路径中的“http://localhost:9001/”部分,页面上结果如下:
    6.使用zuul实现网关

    网关的默认路由规则

    在实际使用过程中,后端的服务个数可能会很多,无论是用URL直接映射还是使用serviceId进行映射都很麻烦,所以spring cloud zuul提供了默认的路由规则。默认情况下,Zuul会代理所有注册到Eureka Server的微服务,并且Zuul的路由规则如下:http://ZUUL_HOST:ZUUL_PORT/微服务在Eureka上的serviceId/**会被转发到serviceId对应的微服务。

    在上面例子的application.properties文件中,注释掉关于路由的配置:

    #zuul.routes.api-a.path=/provider/**
    #zuul.routes.api-a.serviceId=service-provider
    

    重启后访问:http://localhost:8888/service-provider/service-provider/index,发现依然可以访问成功:
    6.使用zuul实现网关

    服务过滤

    在完成了服务路由之后,我们对外开放服务还需要一些安全措施来保护客户端只能访问它应该访问到的资源。所以我们需要利用Zuul的过滤器来实现我们对外服务的安全控制。

    在服务网关中定义过滤器只需要继承ZuulFilter抽象类实现其定义的四个抽象函数就可对请求进行拦截与过滤。

    自定义过滤器的实现,需要继承ZuulFilter,需要重写实现下面四个方法:

    • filterType:返回一个字符串代表过滤器的类型,在zuul中定义了四种不同生命周期的过滤器类型,具体如下:
      pre:可以在请求被路由之前调用
      routing:在路由请求时候被调用
      post:在routing和error过滤器之后被调用
      error:处理请求时发生错误时被调用
    • filterOrder:通过int值来定义过滤器的执行顺序
    • shouldFilter:返回一个boolean类型来判断该过滤器是否要执行,所以通过此函数可实现过滤器的开关。在上例中,我们直接返回true,所以该过滤器总是生效。
    • run:过滤器的具体逻辑。

    在实现了自定义过滤器后,还需要将该过滤器注册到spring容器中才能生效,我们需要在启动类中增加如下代码:

    @Bean
    public AccessFilter accessFilter() {
        return new AccessFilter();
    }
    

    然后,当我们通过Zuul调用服务时,定义的过滤器就会生效。