SpringClound-服务网关

我们前几章已经介绍了SpringClound中的几个核心组件,我们使用Spring Cloud Netflix中的Eureka实现了服务注册中心以及服务注册与发现;而服务间通过Ribbon或Feign实现服务的消费以及均衡负载;通过Spring Cloud Config实现了应用多环境的外部化配置以及版本管理。为了使得服务集群更为健壮,使用Hystrix的融断机制来避免在微服务架构中个别服务出现异常时引起的故障蔓延。
这里写图片描述
在该架构中,我们的服务集群包含:内部服务Service A和Service B,他们都会注册与订阅服务至Eureka Server,而Open Service是一个对外的服务,通过均衡负载公开至服务调用方。
但是我们的权限以及路由如何控制呢?如果在内部实现则会破坏我们的业务逻辑,冗余度增大。所以我们将其处于对外访问最前端的地方,我们需要一个更强大一些的均衡负载器,它就是本文将来介绍的:服务网关。

服务网关是微服务架构中一个不可或缺的部分。通过服务网关统一向外系统提供REST API的过程中,除了具备服务路由、均衡负载功能之外,它还具备了权限控制等功能。Spring Cloud Netflix中的Zuul就担任了这样的一个角色,为微服务架构提供了前门保护的作用,同时将权限控制这些较重的非业务逻辑内容迁移到服务路由层面,使得服务集群主体能够具备更高的可复用性和可测试性。

Zuul

首先我们启动前面文章中的服务注册中心,服务提供者以及两个服务消费者项目,然后访问
http://localhost:8763/add?a=2&b=4
这里写图片描述
http://localhost:8764/add?a=2&b=10
这里写图片描述

可见我们的项目是可以访问的,服务也可以正常被调用。

使用Zull

这里写图片描述
我们需要在应用主类使用@EnableZuulProxy注解开启Zuul

/**
 * 服务网关
 * 2018年6月15日11:40:55
 * yangzhao
 */
@SpringCloudApplication
@EnableZuulProxy//开启服务网关

public class ZuulApplication {

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

Zuul配置

服务路由

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

在Zuul中提供了两种映射方式:

  • 通过url直接映射,我们可以如下配置:
    zuul:
      routes:
         api-c:
          path: /api-c/**
          url: http://localhost:8764/


    eureka:
      client:
        serviceUrl:
          defaultZone: http://localhost:8761/eureka/
    server:
      port: 8765
    spring:
      application:
        name: service-zuul

该配置,定义了,所有到Zuul的中规则为:/api-c/**的访问都映射到http://localhost:8764/上,也就是说当我们访问http://localhost:8765/api-c/add?a=1&b=2的时候,Zuul会将该请求路由到:http://localhost:8764/add?a=1&b=2上。
其中,配置属性zuul.routes.api-c.path中的api-c部分为路由的名字,可以任意定义,但是一组映射关系的path和url要相同

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

针对我们在准备工作中实现的两个微服务service-ribbon和service-feign,定义了两个路由api-a和api-b来分别映射。另外为了让Zuul能发现service-ribbon和service-feign,也加入了eureka的配置。

尝试通过服务网关来访问service-A和service-B,根据配置的映射关系,分别访问下面的url

推荐使用serviceId的映射方式,除了对Zuul维护上更加友好之外,serviceId映射方式还支持了断路器,对于服务故障的情况下,可以有效的防止故障蔓延到服务网关上而影响整个系统的对外服务

服务过滤

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

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

@Component
public class AccessFilter extends ZuulFilter {


    /**
     * 返回一个字符串代表过滤器的类型,在zuul中定义了四种不同生命周期的过滤器类型,具体如下:
     * pre:可以在请求被路由之前调用
       routing:在路由请求时候被调用
       post:在routing和error过滤器之后被调用
       error:处理请求时发生错误时被调用
     * @return
     */
    @Override
    public String filterType() {
        return "pre";
    }


    /**
     * 通过int值来定义过滤器的执行顺序
     * @return
     */
    @Override
    public int filterOrder() {
        return 0;
    }


    /**
     * 返回一个boolean类型来判断该过滤器是否要执行,所以通过此函数可实现过滤器的开关。
     * 在上例中,我们直接返回true,所以该过滤器总是生效。
     * @return
     */
    @Override
    public boolean shouldFilter() {
        return true;
    }

    @Override
    public Object run() {
        RequestContext ctx = RequestContext.getCurrentContext();
        HttpServletRequest request = ctx.getRequest();


        Object accessToken = request.getParameter("yangzhao");
        if(accessToken == null) {
            ctx.setSendZuulResponse(false);
            ctx.setResponseStatusCode(401);
            return null;
        }
        return null;
    }

}

接下来启动Zull项目,访问
http://localhost:8765/api-a/add?a=2&b=4&yangzhao=1
这里写图片描述
http://localhost:8765/api-b/add?a=2&b=10&yangzhao
这里写图片描述
http://localhost:8765/api-a/add?a=2&b=4
这里写图片描述

生命周期
这里写图片描述

最后,总结一下为什么服务网关是微服务架构的重要部分,是我们必须要去做的原因:

  • 不仅仅实现了路由功能来屏蔽诸多服务细节,更实现了服务级别、均衡负载的路由。
  • 实现了接口权限校验与微服务业务逻辑的解耦。通过服务网关中的过滤器,在各生命周期中去校验请求的内容,将原本在对外服务层做的校验前移,保证了微服务的无状态性,同时降低了微服务的测试难度,让服务本身更集中关注业务逻辑的处理。
  • 实现了断路器,不会因为具体微服务的故障而导致服务网关的阻塞,依然可以对外服务。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值