美文网首页
SpringCloud(四)zuul网关

SpringCloud(四)zuul网关

作者: 茧铭 | 来源:发表于2019-05-19 11:06 被阅读0次

在微服务项目搭建之后,我们不可能让客户知道所有的微服务,让客户进行针对性地使用某一个或者几个服务。我们应当有一个统一的请求入口,这个入口替服务器拦截所有的请求,并将请求分发到对应的服务中去调用,这就是服务网关。那么作为项目的唯一入口,服务网关应当有一些必要的特性:

  1. 稳定性,高可用
  2. 性能和并发性
  3. 安全
  4. 扩展性

平时我们使用到的服务网关最多的就是Nginx + lua的形式,Nginx凭借性能的优势占据了网关服务的很大一部分市场。在SpringCloud全家桶中Netflix给我们提供了他自己的解决方案智能路由Zuul,相对而言Zuul提供了更多有意思的功能如身份验证、服务迁移、分级卸载等。至于性能,它的第一个版本的性能应该是差于Nginx的,不过也在后续的版本中对它的性能进行了升级了。

Zuul原理

zuul的核心是一系列的过滤器,这些过滤器分位四个类型
"pre":位置在路由请求到服务调用之前,一般可用于数据校验和限流等
"route":这类过滤器将请求路由到微服务,用于构建发送给微服务的请求,并发起微服务请求。
"post":这类过滤器在路由到微服务之后请求,可以对返回的数据进行处理或包装
"error":其他三类过滤器执行中如果发生错误,会执行该类过滤器。


网络图片

Zuul大部分功能都是通过过滤器来实现的,这些过滤器类型对应于请求的典型生命周期。

Zuul使用

新建一个名为zuul的modular,引入依赖如下

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

启动类上增加注解@EnableZuulProxy

@SpringBootApplication
@EnableZuulProxy
public class ZuulApplication {

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

}

配置文件bootstrap.yml

eureka:
  client:
    service-url:
      defaultZone: http://root:root@localhost:1001/eureka/

spring:
  application:
    name: zuul
  cloud:
    config:
      discovery:
        enabled: true
        service-id: config
      label: master
      profile: dev

github上面的 /zuul-dev.yml

server:
  port: 2992
zuul:
  routes:
    xxxxx:
      path: /api-product/**
      serviceId: product

上面这段配置很明显是对product服务做了什么。我这里依次将eureka、config、zuul、product四个服务启动起来,通过以下三种方式去获取调用product的一个接口,结果如下:

localhost:3003/product/findByProductStatus?productStatus=1
localhost:2992/api-product/product/findByProductStatus?productStatus=1
localhost:2992/product/product/findByProductStatus?productStatus=1


其实很明显能看出来,zuul的端口为2992,后面连个请求已经可以通过zuul路由到了product服务上。其中第三个请求中有两个product,第一个是serviceId服务ID,后面的是完整的请求路径。第二个请求正如zuul-dev.yml上所示,将product服务映射到了一个自定义的路径“/api-product/**”下,因此也能获取到同意的服务。在配置中有个"xxxxx"的内容,这个内容名字可以自定义,也就是将该路由规则命名而已,没有实际意义。

这样的配置还有一种更加简单的配置方式

zuul:
  routes:
    product: /api-product/**
    # product就不是随便命名的了,而是product的服务serviceId
Cookie相关

我们平常使用cookie是时候,是可以直接从HttpServletRequest中获取到信息的,但是每当请求经过了一层zuul的转发之后,cookie就不能直接从request中获取到了。我们需要加入一下配置

zuul:
  routes:
    xxxxx:
      path: /api-product/**
      serviceId: product
      sensitiveHeaders: 

即在对应的服务路由配置下,加载一个sensitiveHeaders的空值,在Zuul的配置信息类ZuulProperties中,sensitiveHeaders参数有些默认值,它的作用是默认屏蔽掉这些内容的传递,其中就包括cookie和Authorization,因此我们想要使用Cookie的话就可以把其中的Cookie去掉,我这里直接设置为空了。


此外,在里面还有一些参数我们可能也会用到,比如说有三个ignored开头的参数,和.gitignore类似,它们的作用是在不同维度划分的情况下,将某一些接口不适用zuul路由,配置了之后再通过zuul访问是找不到的(通常这些接口都是服务之间调用的,而不能被外部直接调用)

举例,加入配置后重启项目:

zuul:
  ignored-patterns:
    - /api-product/product/findByProductStatus
##  - /product/product/findByProductStatus

再次访问,结果如下
localhost:2992/api-product/product/findByProductStatus?productStatus=1
localhost:2992/product/product/findByProductStatus?productStatus=1


因此呢,ignored-patterns就可以达成我们屏蔽某些接口的效果,这个里面也可以使用 ** 通配符等。

bus-refresh配置

配置config通过bus-refresh刷新:之前的order和product的配置方式我们知道了要在对应的Controller上添加一个@RefreshScope,但是Zuul的项目看起来没有什么Controller,我们可以添加到这里来

新建一个这样的类,在原有的ZuulProperties类上加入@RefreshScope即可

@Component
public class ZuulConfig {

    @ConfigurationProperties("zuul")
    @RefreshScope
    public ZuulProperties zuulProperties(){
        return new ZuulProperties();
    }

}

自定义过滤器

原理的时候已经提到了,我们可以重写一些过滤器。比如说下面这个,这个例子是我在网上看到别人做的,我拿过来试了一下,自己写一下也能更好地理解它的原理:增加一个类型是pre的过滤器,要求请求中必须带有"token"参数,否则将不会路由过去。

在这之前,先看看zuul原本有哪些已经存在的过滤器

Zuul中默认实现的Filter(https://www.jianshu.com/p/8ea59534bedb

按照上面的排列,接下来我根据token的逻辑,创建一个Filter内容如下:

其中某些参数如PRE_TYPE、PRE_DECORATION_FILTER_ORDER 都是从 FilterConstants 中取出使用的,这些值对应了上面zuul的默认实现的值

@Component
public class TokenCheckFilter extends ZuulFilter{
    
    /**  表示类型是pre  */
    @Override
    public String filterType() {
        return PRE_TYPE;
    }
    
    /**  配许的序号为5-1 = 4  */
    @Override
    public int filterOrder() {
        return PRE_DECORATION_FILTER_ORDER - 1;
    }

    /** 为true表示可用,false代表该filter暂不拦截 */
    @Override
    public boolean shouldFilter() {
        return true;
    }

    /** 具体逻辑,没有token则不路由请求,且返回状态码401 */
    @Override
    public Object run() throws ZuulException {
        RequestContext ctx = RequestContext.getCurrentContext();
        HttpServletRequest request = ctx.getRequest();
        String token = request.getParameter("token");
        if (StringUtils.isEmpty(token)){
            /**  如果没有token或为空,不路由请求到服务 */
            ctx.setSendZuulResponse(false);
            ctx.setResponseStatusCode(HttpStatus.SC_UNAUTHORIZED);
        }

        return null;
    }
}

测试结果如下:


最后在说一下禁用指定的Filter的配置,如下所示,通过对指定过滤器的配置,可以单独关闭或者启动一个或者多个过滤器

zuul:
    TokenCheckFilter:
        pre:
            disable: true

相关文章

网友评论

      本文标题:SpringCloud(四)zuul网关

      本文链接:https://www.haomeiwen.com/subject/jtveoqtx.html