服务器之家:专注于服务器技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|JavaScript|易语言|

服务器之家 - 编程语言 - Java教程 - SpringCloud实战之Zuul网关服务

SpringCloud实战之Zuul网关服务

2021-05-03 10:35蜗居在小黑屋操控世界 Java教程

服务网关是分布式架构中不可缺少的组成部分,是外部网络和内部服务之间的屏障。这篇文章主要介绍了SpringCloud实战之Zuul网关服务。一起跟随小编过来看看吧

为什么需要网关呢?

我们知道我们要进入一个服务本身,很明显我们没有特别好的办法,直接输入ip地址+端口号,我们知道这样的做法很糟糕的,这样的做法大有问题,首先暴露了我们实体机器的ip地址,别人一看你的ip地址就知道服务部署在哪里,让别人很方便的进行攻击操作。

第二,我们这么多服务,我们是不是要挨个调用它呀,我们这里假设做了个权限认证,我们每一个客户访问的都是跑在不同机器上的不同的jvm上的服务程序,我们每一个服务都需要一个服务认证,这样做烦不烦呀,明显是很烦的。

那么我们这时候面临着这两个及其总要的问题,这时我们就需要一个办法解决它们。首先,我们看ip地址的暴露和ip地址写死后带来的单点问题,我是不是对这么服务本身我也要动态的维护它服务的列表呀,我需要调用这服务本身,是不是也要一个负载均衡一样的玩意,

还有关于ip地址暴露的玩意,我是不是需要做一个代理呀,像nginx的反向代理一样的东西,还有这玩意上部署公共的模块,比如所有入口的权限校验的东西。因此我们现在需要zuul api网关。它就解决了上面的问题,你想调用某个服务,它会给你映射,把你服务的ip地址映射成

某个路径,你输入该路径,它匹配到了,它就去替你访问这个服务,它会有个请求转发的过程,像nginx一样,服务机器的实例具体实力,它不会直接去访问ip,它会去eureka注册中心拿到服务的实例id,即服务的名字。我再次使用客户端的负载均衡ribbon访问其中服务实例中的一台。

api网关主要为了服务本身对外的调用该怎么调用来解决的,还有解决权限校验的问题,你可以在这里整合调用一系列过滤器的,例如整合shiro,springsecurity之类的东西。

SpringCloud实战之Zuul网关服务

zuul可以通过加载动态过滤机制,从而实现以下各项功能:

1.验证与安全保障: 识别面向各类资源的验证要求并拒绝那些与要求不符的请求。

2.审查与监控: 在边缘位置追踪有意义数据及统计结果,从而为我们带来准确的生产状态结论。

3.动态路由: 以动态方式根据需要将请求路由至不同后端集群处。

4.压力测试: 逐渐增加指向集群的负载流量,从而计算性能水平。

5.负载分配: 为每一种负载类型分配对应容量,并弃用超出限定值的请求。

6.静态响应处理: 在边缘位置直接建立部分响应,从而避免其流入内部集群。

7.多区域弹性: 跨越aws区域进行请求路由,旨在实现elb使用多样化并保证边缘位置与使用者尽可能接近。

接着下来进行实战小demo

第一步,在原来的工程下,新建一个zuul模块,引入依赖,代码如下:

?
1
2
3
4
5
6
7
8
9
10
11
<dependency>
      <groupid>org.springframework.cloud</groupid>
      <artifactid>spring-cloud-starter-eureka</artifactid>
      <version>1.3.5.release</version>
    </dependency>
 
    <dependency>
      <groupid>org.springframework.cloud</groupid>
      <artifactid>spring-cloud-starter-zuul</artifactid>
      <version>1.3.5.release</version>
    </dependency>

接着在启动类上打上@enablezuulproxy注解,代码如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
server:
 port: 5000
spring:
 application:
  name: api-geteway
zuul:
 routes:
#标识你服务的名字,这里可以自己定义,一般方便和规范来讲还是跟自己服务的名字一样
  hello-service:
#服务映射的路径,通过这路径就可以从外部访问你的服务了,目的是为了不爆露你机器的ip,面向服务的路由了,给你选一个可用的出来,
#这里zuul是自动依赖hystrix,ribbon的,不是面向单机
   path: /hello-service/**
#这里一定要是你eureka注册中心的服务的名称,是所以这里配置serviceid因为跟eureka结合了,如果单独使用zuul,那么就必须写自己机器的ip了,
#如url:http://localhost:8080/ 这样的不好就是写死ip了,万一这ip挂了,这高可用性,服务注册那套东西就用不起来了
   serviceid: hello-service
 
eureka:
#客户端
 client:
#注册中心地址
  service-url:
   defaultzone: http://localhost:8888/eureka/,http://localhost:8889/eureka/

接着启动先前文章中的注册中心和两个hello-service服务提供者,接着我们运行,看一下它的请求转发功能,看他有没有轮询进入两个服务,

输入localhost:5000/hello-service/hello,如下:

SpringCloud实战之Zuul网关服务

接着再刷新一遍:

SpringCloud实战之Zuul网关服务

可以看到zuul进行了请求分发了。它是根据你的服务名字hello-servie来映射到具体的机器上,这不就是一个反向代理的功能吗?

zuul还能进行请求过滤,那么我们进行一下token校验来演示一下,首先我们需要先新建一个tokenfilter类来继承zuulfilter这个类,实现它的四个接口,代码如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
package hjc.zuul;
 
import com.netflix.zuul.zuulfilter;
import com.netflix.zuul.context.requestcontext;
 
import javax.servlet.http.httpservletrequest;
 
/**
 * created by cong on 2018/5/18.
 */
public class tokenfilter extends zuulfilter {
  //四种类型:pre,routing,error,post
  //pre:主要用在路由映射的阶段是寻找路由映射表的
  //routing:具体的路由转发过滤器是在routing路由器,具体的请求转发的时候会调用
  //error:一旦前面的过滤器出错了,会调用error过滤器。
  //post:当routing,error运行完后才会调用该过滤器,是在最后阶段的
  @override
  public string filtertype() {
    return "pre";
  }
 
  //自定义过滤器执行的顺序,数值越大越靠后执行,越小就越先执行
  @override
  public int filterorder() {
    return 0;
  }
 
  //控制过滤器生效不生效,可以在里面写一串逻辑来控制
  @override
  public boolean shouldfilter() {
    return true;
  }
 
  //执行过滤逻辑
  @override
  public object run() {
 
    requestcontext context = requestcontext.getcurrentcontext();
    httpservletrequest request = context.getrequest();
    string token = request.getparameter("token");
    if (token == null){
      context.setsendzuulresponse(false);
      context.setresponsestatuscode(401);
      context.setresponsebody("unauthrized");
 
 
      return null;
    }
    return null;
  }
}

filtertype:返回一个字符串代表过滤器的类型,在zuul中定义了四种不同生命周期的过滤器类型,具体如下:

1. pre :可以在请求被路由之前调用,用在路由映射的阶段是寻找路由映射表的

2.route :在路由请求时候被调用,具体的路由转发过滤器是在routing路由器具体的请求转发的时候会调用

3. error :处理请求时发生错误时被调用

4. post :当routing,error运行完后才会调用该过滤器,是在最后阶段的

这里声明一下zuul过滤器执行网络请求发生的异常,过滤器里面是不能直接将try-catch捕捉的异常抛出给页面的。应用程序抛出的异常是可以返回出的需解决办法就是在catch里面用context.set()方法返回给页面。如下:

?
1
2
3
4
5
6
7
8
try{
  业务逻辑......
}catch(exception e){
    requestcontext context = requestcontext.getcurrentcontext();
     context.set("error.status_code",401);
      context.set("error.exception",e);
      context.set("error.message","sfdfsdf");
}

接着,你还需要把这个过滤器加入spring中,让spring管理,代码如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package hjc;
import hjc.zuul.tokenfilter;
import org.springframework.boot.springapplication;
import org.springframework.boot.autoconfigure.springbootapplication;
import org.springframework.cloud.netflix.zuul.enablezuulproxy;
import org.springframework.context.annotation.bean;
@springbootapplication
@enablezuulproxy
public class zuulapplication {
 
  public static void main(string[] args) {
    springapplication.run(zuulapplication.class, args);
  }
 
  //将过滤器交给spring管理
  @bean
  public tokenfilter tokenfilter(){
    return new tokenfilter();
  }
}

接着,让我们启动启动类,先进行不带token的访问,如下:

SpringCloud实战之Zuul网关服务

可以看到,返回一个没权限的信息,这里要说一下,token一般都是放在请求头中的,这里我们只是为了演示才没那么干,

接着将token带上再去访问,如下:

SpringCloud实战之Zuul网关服务

可以看到这是已经将我们的请求放过去了。

这里我还要讲一下什么是默认路由,将zuul的配置删除路由配置,如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
server:
 port: 5000
spring:
 application:
  name: api-geteway
 
 
eureka:
#客户端
 client:
#注册中心地址
  service-url:
   defaultzone: http://localhost:8888/eureka/,http://localhost:8889/eureka/

接着,重启继续访问,如下:

SpringCloud实战之Zuul网关服务

可以看到,还是能继续访问,我们什么都没配,居然还能访问,那是因为,这里默认用你的服务名字hello-service自动声明了。

那么,如果说我不想让它帮我自动声明,我要我自己定义,那么可以在yml配置文件中使用zuu.ignored-services就可以把自己像过滤的过滤,如下:”

?
1
2
3
4
zuul:
#如果ignored-services:* 表示所有的默认路由都失效了,要自己一个个配,没人会那么操蛋,除非遇到奇葩业务
 
 ignored-services:

接着我们再说一下映射规则,比方说

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
zuul:
 routes:
#标识你服务的名字,这里可以自己定义,一般方便和规范来讲还是跟自己服务的名字一样
  hello-service:
#服务映射的路径,通过这路径就可以从外部访问你的服务了,目的是为了不爆露你机器的ip,面向服务的路由了,给你选一个可用的出来,
#这里zuul是自动依赖hystrix,ribbon的,不是面向单机
   path: /hello-service/**
#这里一定要是你eureka注册中心的服务的名称,是所以这里配置serviceid因为跟eureka结合了,如果单独使用zuul,那么就必须写自己机器的ip了,
#如url:http://localhost:8080/ 这样的不好就是写死ip了,万一这ip挂了,这高可用性,服务注册那套东西就用不起来了
   serviceid: hello-service
 
zuul:
 routes:
  hello-service:
   path: /hello-service/ext/**
   serviceid: hello-service

这里的两个zuul配置映射路径都有/hello-service/,可以看到/hello-service/**是包括/hello-service/ext/**的,这两个路径进行匹配的时候是不是有冲突呀,怎么处理呢?谁先匹配呢?

这里是yml中定义的顺序来匹配的。如果是application.properties格式的配置文件,它这个顺序是不能保证的,yml格式的配置文件是有顺序的,可以保证,这里要注意下一下。

如果我们想定义一下匹配规则怎么办呢?那么我们就需要在启动类中定义一个bean,这个类就是决定你的路由的,如下:

SpringCloud实战之Zuul网关服务

这里就不演示了,需要用到的时候自己再去慢慢查找资料吧。

还有就是ignored-patterns:,如下:

?
1
2
3
4
5
6
7
8
9
10
11
zuul:
 routes:
#标识你服务的名字,这里可以自己定义,一般方便和规范来讲还是跟自己服务的名字一样
  hello-service:
#服务映射的路径,通过这路径就可以从外部访问你的服务了,目的是为了不爆露你机器的ip,面向服务的路由了,给你选一个可用的出来,
#这里zuul是自动依赖hystrix,ribbon的,不是面向单机
   path: /hello-service/**
#这里一定要是你eureka注册中心的服务的名称,是所以这里配置serviceid因为跟eureka结合了,如果单独使用zuul,那么就必须写自己机器的ip了,
#如url:http://localhost:8080/ 这样的不好就是写死ip了,万一这ip挂了,这高可用性,服务注册那套东西就用不起来了
   serviceid: hello-service
 ignored-patterns: /hello/**

ignored-patterns:表示屏蔽掉/hello/**的路径,就算你/hello-service/hello/**也不行,照样屏蔽。这个配置我们可以进一步细化,比如说我不想给/hello接口路由,那我们可以按照上面方式配置

如果我们还想配置一个服务的前缀该怎么办?代码如下:

?
1
2
3
4
5
6
7
8
9
10
11
zuul:
 routes:
#标识你服务的名字,这里可以自己定义,一般方便和规范来讲还是跟自己服务的名字一样
  hello-service:
#服务映射的路径,通过这路径就可以从外部访问你的服务了,目的是为了不爆露你机器的ip,面向服务的路由了,给你选一个可用的出来,
#这里zuul是自动依赖hystrix,ribbon的,不是面向单机
   path: /hello-service/**
#这里一定要是你eureka注册中心的服务的名称,是所以这里配置serviceid因为跟eureka结合了,如果单独使用zuul,那么就必须写自己机器的ip了,
#如url:http://localhost:8080/ 这样的不好就是写死ip了,万一这ip挂了,这高可用性,服务注册那套东西就用不起来了
   serviceid: hello-service
 prefix: /api/**

可以看到那么你访问的服务都必须要加/api/前缀,例如/api/hello-service/**

如果我们还想进行一个路径访问就跳转到我的本地,那该怎么办呢?

我希望用户在访问/local时能够自动跳转到这个方法上来处理,那么此时我们需要用到zuul的本地跳转,配置方式如下:

?
1
2
3
4
5
6
7
zuul:
 prefix: /api
 ignored-patterns: /**/hello/**
 routes:
  local:
   path: /hello-service/**
   url: forward:/local

我们常用的一些,对接springsecurity,或者是一些第三方组件,它们会获取你的一些cookie信息,那么zuul网关为了安全起见,把你的cookie信息都给干掉了,这个是没办法去搞cookie的。它是默认干掉的。

这里zuul提供了zuul.sensitive-headers来给你搞这些cookie,header,这些信息不要进行过滤。控制你的敏感信息。

默认情况下,敏感的头信息无法经过api网关进行传递,我们可以通过如下配置使之可以传递:

?
1
2
3
4
5
6
zuul:
 routes:
  hello-service:
   path: /hello-service/**
   serviceid: hello-service
 sensitive-headers:  cookie,header之类额东西

还可以配合hystrix的一些详细配置一起使用,前面也讲过了。这里就不说了

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。

延伸 · 阅读

精彩推荐