浅谈Spring Cloud中的API网关服务Zuul

到目前为止,我们Spring Cloud中的内容已经介绍了很多了,Ribbon、Hystrix、Feign这些知识点大家都耳熟能详了,我们在前文也提到过微服务就是把一个大的项目拆分成很多小的独立模块,然后通过服务治理让这些独立的模块配合工作等。那么大家来想这样两个问题:1.如果我的微服务中有很多个独立服务都要对外提供服务,那么对于开发人员或者运维人员来说,他要如何去管理这些接口?特别是当项目非常大非常庞杂的情况下要如何管理?2.权限管理也是一个老生常谈的问题,在微服务中,一个独立的系统被拆分成很多个独立的模块,为了确保安全,我难道需要在每一个模块上都添加上相同的鉴权代码来确保系统不被非法访问?如果是这样的话,那么工作量就太大了,而且维护也非常不方便。

为了解决上面提到的问题,我们引入了API网关的概念,API网关是一个更为智能的应用服务器,它有点类似于我们微服务架构系统的门面,所有的外部访问都要先经过API网关,然后API网关来实现请求路由、负载均衡、权限验证等功能。Spring Cloud中提供的Spring Cloud Zuul实现了API网关的功能,本文我们就先来看看Spring Cloud Zuul的一个基本使用。

构建网关

网关的构建我们通过下面三个步骤来实现。

1.创建Spring Boot工程并添加依赖

首先我们创建一个普通的Spring Boot工程名为api-gateway,然后添加相关依赖,这里我们主要添加两个依赖spring-cloud-starter-zuul和spring-cloud-starter-eureka,spring-cloud-starter-zuul依赖中则包含了ribbon、hystrix、actuator等,如下:

<parent>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-parent</artifactId>
  <version>1.5.7.RELEASE</version>
  <relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
  <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
  <java.version>1.8</java.version>
  <spring-cloud.version>Dalston.SR3</spring-cloud.version>
</properties>
<dependencies>
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter</artifactId>
  </dependency>
  <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-zuul</artifactId>
  </dependency>
  <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-eureka</artifactId>
  </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>

2.添加注解

然后在入口类上添加@EnableZuulProxy注解表示开启Zuul的API网关服务功能,如下:

@SpringBootApplication
@EnableZuulProxy
public class ApiGatewayApplication {

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

3.配置路由规则

application.properties文件中的配置可以分为两部分,一部分是Zuul应用的基础信息,还有一部分则是路由规则,如下:

# 基础信息配置
spring.application.name=api-gateway
server.port=2006
# 路由规则配置
zuul.routes.api-a.path=/api-a/**
zuul.routes.api-a.serviceId=feign-consumer

# API网关也将作为一个服务注册到eureka-server上
eureka.client.service-url.defaultZone=http://localhost:1111/eureka/

我们在这里配置了路由规则所有符合/api-a/**的请求都将被转发到feign-consumer服务上,至于feign-consumer服务的地址到底是什么则由eureka-server去分析,我们这里只需要写上服务名即可。以上面的配置为例,如果我请求 http://localhost:2006/api-a/hello1 接口则相当于请求 http://localhost:2005/hello1 (我这里feign-consumer的地址为 http://localhost:2005 ),我们在路由规则中配置的api-a是路由的名字,可以任意定义,但是一组path和serviceId映射关系的路由名要相同。

OK,做好这些之后,我们依次启动我们的eureka-server、provider和feign-consumer,然后访问如下地址 http://localhost:2006/api-a/hello1 ,访问结果如下:

看到这个效果说明我们的API网关服务已经构建成功了,我们发送的符合路由规则的请求自动被转发到相应的服务上去处理了。

请求过滤

构建好了网关,接下来我们就来看看如何利用网关来实现一个简单的权限验证。这里就涉及到了Spring Cloud Zuul中的另外一个核心功能:请求过滤。请求过滤有点类似于Java中Filter过滤器,先将所有的请求拦截下来,然后根据现场情况做出不同的处理,这里我们就来看看Zuul中的过滤器要如何使用。很简单,两个步骤:

1.定义过滤器

首先我们定义一个过滤器继承自ZuulFilter,如下:

public class PermisFilter extends ZuulFilter {
  @Override
  public String filterType() {
    return "pre";
  }

  @Override
  public int filterOrder() {
    return 0;
  }

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

  @Override
  public Object run() {
    RequestContext ctx = RequestContext.getCurrentContext();
    HttpServletRequest request = ctx.getRequest();
    String login = request.getParameter("login");
    if (login == null) {
      ctx.setSendZuulResponse(false);
      ctx.setResponseStatusCode(401);
      ctx.addZuulResponseHeader("content-type","text/html;charset=utf-8");
      ctx.setResponseBody("非法访问");
    }
    return null;
  }
}

关于这个类我说如下几点:

1.filterType方法的返回值为过滤器的类型,过滤器的类型决定了过滤器在哪个生命周期执行,pre表示在路由之前执行过滤器,其他可选值还有post、error、route和static,当然也可以自定义。

2.filterOrder方法表示过滤器的执行顺序,当过滤器很多时,这个方法会有意义。

3.shouldFilter方法用来判断过滤器是否执行,true表示执行,false表示不执行,在实际开发中,我们可以根据当前请求地址来决定要不要对该地址进行过滤,这里我直接返回true。

4.run方法则表示过滤的具体逻辑,假设请求地址中携带了login参数的话,则认为是合法请求,否则就是非法请求,如果是非法请求的话,首先设置ctx.setSendZuulResponse(false);表示不对该请求进行路由,然后设置响应码和响应值。这个run方法的返回值在当前版本(Dalston.SR3)中暂时没有任何意义,可以返回任意值。

2.配置过滤器Bean

然后在入口类中配置相关的Bean即可,如下:

@Bean
PermisFilter permisFilter() {
  return new PermisFilter();
}

此时,如果我们访问 http://localhost:2006/api-a/hello1 ,结果如下:

如果给请求地址加上login参数,则结果如下:

总结

到这里小伙伴们应该已经见识到Spring Cloud Zuul的强大之处了吧,API网关作为系统的的统一入口,将微服务中的内部细节都屏蔽掉了,而且能够自动的维护服务实例,实现负载均衡的路由转发,同时,它提供的过滤器为所有的微服务提供统一的权限校验机制,使得服务自身只需要关注业务逻辑即可。

Zuul的入门知识我们就先介绍到这里,小伙伴们有问题欢迎留言讨论。以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • spring cloud zuul修改请求url的方法

    前言 在日常开发中,除了修改请求参数.设置响应header,响应body外,还有一种需求就是url重新,或者是修改url,这里简述一下怎么在zuul修改url.话不多说了,来一起看看详细的介绍吧. 转发配置 demo: ribbon: NIWSServerListClassName: com.netflix.loadbalancer.ConfigurationBasedServerList listOfServers: 192.168.99.100,192.168.99.101 zuul: ro

  • 深入解析Spring Cloud内置的Zuul过滤器

    前言 Spring Cloud默认为Zuul编写并启用了一些过滤器,这些过滤器有什么作用呢?我们不妨按照@EnableZuulServer.@EnableZuulProxy两个注解进行展开,相信大家对这两个注解都不陌生(至少都见过吧).如果觉得陌生也没有关系,可将@EnableZuulProxy简单理解为@EnableZuulServer的增强版.事实上,当Zuul与Eureka.Ribbon等组件配合使用时, @EnableZuulProxy是我们常用的注解. 在Spring Cloud的官方

  • spring cloud如何修复zuul跨域配置异常的问题

    前言 本文主要给大家介绍一下在zuul进行跨域配置的时候出现异常该如何解决的方法,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧. 异常 The 'Access-Control-Allow-Origin' header contains multiple values '*, *', but only one is allowed 实例 Access-Control-Allow-Credentials:true Access-Control-Allow-Credentials:t

  • 利用Spring Cloud Zuul实现动态路由示例代码

    前言 本文主要给大家介绍了关于Spring Cloud Zuul实现动态路由的相关内容,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧. Zuul 是提供动态路由,监控,弹性,安全等的边缘服务.Zuul 相当于是设备和 Netflix 流应用的 Web 网站后端所有请求的前门. Zuul 可以适当的对多个 Amazon Auto Scaling Groups 进行路由请求. 首先新建maven项目,加入如下依赖 <dependencyManagement> <depend

  • 深入理解Spring Cloud Zuul过滤器

    前言 过滤器是Zuul的核心组件,这篇文章我们来详细讨论Zuul的过滤器.下面话不多说,来看看详细的介绍吧. 过滤器类型与请求生命周期 Zuul大部分功能都是通过过滤器来实现的.Zuul中定义了四种标准过滤器类型,这些过滤器类型对应于请求的典型生命周期. (1) PRE:这种过滤器在请求被路由之前调用.我们可利用这种过滤器实现身份验证.在集群中选择请求的微服务.记录调试信息等. (2) ROUTING:这种过滤器将请求路由到微服务.这种过滤器用于构建发送给微服务的请求,并使用Apache Htt

  • SpringCloud实战小贴士之Zuul的路径匹配

    不论是使用传统路由的配置方式还是服务路由的配置方式,我们都需要为每个路由规则定义匹配表达式,也就是上面所说的 path 参数.在Zuul中,路由匹配的路径表达式采用了Ant风格定义. Ant风格的路径表达式使用起来非常简单,它一共有下面这三种通配符: 通配符 说明 ? 匹配任意的单个字符 * 匹配任意数量的字符 ** 匹配任意数量的字符,支持多级目录 我们可以通过下表的示例来进一步理解这三个通配符的含义并参考着来使用: URL路径 说明 /user-service/? 它可以匹配 /user-s

  • 浅谈Spring Cloud中的API网关服务Zuul

    到目前为止,我们Spring Cloud中的内容已经介绍了很多了,Ribbon.Hystrix.Feign这些知识点大家都耳熟能详了,我们在前文也提到过微服务就是把一个大的项目拆分成很多小的独立模块,然后通过服务治理让这些独立的模块配合工作等.那么大家来想这样两个问题:1.如果我的微服务中有很多个独立服务都要对外提供服务,那么对于开发人员或者运维人员来说,他要如何去管理这些接口?特别是当项目非常大非常庞杂的情况下要如何管理?2.权限管理也是一个老生常谈的问题,在微服务中,一个独立的系统被拆分成很

  • 浅谈Spring Cloud Netflix-Ribbon灰度方案之Zuul网关灰度

    Eureka默认集成了Ribbon,所以Ribbon的灰度实现原理就是借助服务注册到Eureka中的eureka.instance.metadata-map的内容来进行匹配的. Zuul网关的灰度实现也是借助了一个Ribbon的插件来实现,相对比较简单. 项目环境说明:有两个eureka的服务端(eureka-server),有两个相同的后端服务(service-sms),有一个网关服务(cloud-zuul). 1.网关的依赖: <?xml version="1.0" enco

  • 浅谈spring容器中bean的初始化

    当我们在spring容器中添加一个bean时,如果没有指明它的scope属性,则默认是singleton,也就是单例的. 例如先声明一个bean: public class People { private String name; private String sex; public String getName() { return name; } public void setName(String name) { this.name = name; } public String get

  • 浅谈Spring Cloud Ribbon的原理

    Ribbon是Netflix发布的开源项目,主要功能是提供客户端的软件负载均衡算法,将Netflix的中间层服务连接在一起.Ribbon客户端组件提供一系列完善的配置项如连接超时,重试等.简单的说,就是在配置文件中列出Load Balancer(简称LB)后面所有的机器,Ribbon会自动的帮助你基于某种规则(如简单轮询,随即连接等)去连接这些机器.我们也很容易使用Ribbon实现自定义的负载均衡算法. 说起负载均衡一般都会想到服务端的负载均衡,常用产品包括LBS硬件或云服务.Nginx等,都是

  • 浅谈Spring Cloud zuul http请求转发原理

    spring cloud 网关,依赖于netflix 下的zuul 组件 zuul 的流程是,自定义 了ZuulServletFilter和zuulServlet两种方式,让开发者可以去实现,并调用 先来看下ZuulServletFilter的实现片段 @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) thr

  • 浅谈Spring Cloud下微服务权限方案

    背景 从传统的单体应用转型Spring Cloud的朋友都在问我,Spring Cloud下的微服务权限怎么管?怎么设计比较合理?从大层面讲叫服务权限,往小处拆分,分别为三块:用户认证.用户权限.服务校验. 用户认证 传统的单体应用可能习惯了session的存在,而到了Spring cloud的微服务化后,session虽然可以采取分布式会话来解决,但终究不是上上策.开始有人推行Spring Cloud Security结合很好的OAuth2,后面为了优化OAuth 2中Access Token

  • 浅谈Spring Boot中Redis缓存还能这么用

    经过Spring Boot的整合封装与自动化配置,在Spring Boot中整合Redis已经变得非常容易了,开发者只需要引入Spring Data Redis依赖,然后简单配下redis的基本信息,系统就会提供一个RedisTemplate供开发者使用,但是今天松哥想和大伙聊的不是这种用法,而是结合Cache的用法.Spring3.1中开始引入了令人激动的Cache,在Spring Boot中,可以非常方便的使用Redis来作为Cache的实现,进而实现数据的缓存. 工程创建 首先创建一个Sp

  • 浅谈Spring Boot中如何干掉if else的方法

    前言 看到crossoverJie的文章<利用策略模式优化过多 if else 代码>后受到启发,可以利用策略模式简化过多的if else代码,文章中提到可以通过扫描实现处理器的自注册,我在这里介绍在Spring Boot框架中的实现方法. 需求 这里虚拟一个业务需求,让大家容易理解.假设有一个订单系统,里面的一个功能是根据订单的不同类型作出不同的处理. 订单实体: public class OrderDTO { private String code; private BigDecimal

  • 浅谈Spring Cloud Eureka 自我保护机制

    自我保护背景 首先对Eureka注册中心需要了解的是Eureka各个节点都是平等的,没有ZK中角色的概念, 即使N-1个节点挂掉也不会影响其他节点的正常运行. 默认情况下,如果Eureka Server在一定时间内(默认90秒)没有接收到某个微服务实例的心跳,Eureka Server将会移除该实例.但是当网络分区故障发生时,微服务与Eureka Server之间无法正常通信,而微服务本身是正常运行的,此时不应该移除这个微服务,所以引入了自我保护机制. 自我保护机制 官方对于自我保护机制的定义:

  • 浅谈Spring AOP中args()和argNames的含义

    args()的作用主要有两点: 1.切入点表达式部分如果增加了args()部分,那么目标方法除了要满足execution部分,还要满足args()对方法参数的要求,对于符合execution表达式,但不符合args参数的方法,不会被植入切面. 2.定义了args()之后,才能把目标方法的参数传入到切面方法的参数中(通过Joinpoint也可以获取参数,但当前方法是直接用切面方法参数接受). 示例1 目标方法: @RestController @RequestMapping("/testAop&q

随机推荐