Spring Cloud 框架 -- Zuul

服务网关

Spring Cloud 中,网关主要有两种实现方案:

  • Zuul

  • Spring Cloud Gateway

由于每一个微服务的地址都有可能发生变化,无法直接对外公布这些服务地址,基于安全以及高内聚低耦合等设计,我们有必要将内部系统和外部系统做一个切割。

一个专门用来处理外部请求的组件,就是服务网关。

  • 权限问题统一处理
  • 数据剪裁和聚合
  • 简化客户端的调用
  • 可以针对不同的客户端提供不同的网关支持

Zuul

Zuul 是 Netflix 公司提供的网关服务,是 Spring Cloud 五大神兽之一:

  • 服务发现——Netflix Eureka

  • 客服端负载均衡——Netflix Ribbon

  • 断路器——Netflix Hystrix

  • 服务网关——Netflix Zuul

  • 分布式配置——Spring Cloud Config

Zuul 的功能如下:

  • 权限控制,可以做认证和授权

  • 监控

  • 动态路由

  • 负载均衡

  • 静态资源处理

Zuul 中的功能基本上都是基于过滤器来实现的,他的过滤器有如下几种类型:

  • PRE:前置过滤器

  • ROUTING :将请求路由到微服务上去

  • POST:过滤器执行完后,会执行它

  • ERROR:在过滤器执行出错时,会执行它

一个 HelloWorld 示例

新建一个 Spring Boot 模块,添加如下依赖:

项目创建成功后,将 zuul 注册到 eureka 上:

spring.application.name=zuul
server.port = 2020
eureka.client.service-url.defaultZone = http://localhost:1111/eureka

然后在启动类上开启网关代理:

@SpringBootApplication
@EnableZuulProxy // 开启网关代理
public class ZuulApplication {

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

}

配置完成后,先启动服务注册中心 eureka

再启动 provider

最后启动 zuul

接下来,在浏览器中,通过 zuul 代理,就可以访问到 provider 。

http://localhost:2020/provider/hello

如下图:

在这个访问地址中,provider 就是要访问的服务名称,/hello 就是要访问的服务接口。

zuul 中的路由规则也可以自己配置,在 application.properties 中配置如下:

zuul.routes.provider = /you/**

上面这个配置,表示,满足这个匹配规则的请求,将被转发到 provider 实例上。

重启 zuul

访问“http://localhost:2020/you/hello”,效果如下:

可以看到,和之前的访问效果是一样的。

Zuul 的请求过滤

对于来自客户端的请求,可以在 zuul 中进行预处理,例如权限判断等。

定义一个简单的过滤器:

@Component
public class PermissFilter extends ZuulFilter {
    /*
    * 过滤器类型,一般是 pre
    * */
    @Override
    public String filterType() {
        return "pre";
    }
    /*
    * 过滤器的优先级
    * */
    @Override
    public int filterOrder() {
        return 0;
    }
    /*
    * 是否过滤
    * */
    @Override
    public boolean shouldFilter() {
        return true;
    }
    /*
    * 核心过滤逻辑写在这里
    * 有返回值,但忽略它
    * */
    @Override
    public Object run() throws ZuulException {
        RequestContext currentContext = RequestContext.getCurrentContext();
        HttpServletRequest request = currentContext.getRequest(); // 获取当前请求
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        if (!"you".equals(username) || !"123".equals(password)){
            // 如果请求条件不满足,直接从这里给出响应
            currentContext.setSendZuulResponse(false);
            currentContext.setResponseStatusCode(401);
            currentContext.addZuulResponseHeader("content-type", "text/html;charset=utf-8");
            currentContext.setResponseBody("非法访问");
        }
        return null;
    }
}

重启 zuul

接下来,发送请求必须带上 username 和password 参数,否则为非法请求 。

http://localhost:2020/you/hello?username=you&password=123 ,效果如下:

若将 password 修改为 1234 ,则为非法请求,效果如下:

Zuul 中的其他配置

匹配规则

例如,有两个服务,一个叫 consumer,另一个叫做 consumer-hello, 在做路由规则配置时,假如出现了如下配置:

zuul.routes.consumer = /consumer/**
zuul.routes.consumer-hello = /consumer/hello/**

此时,如果访问一个地址:http://localhost:2020/consumer/hello/123,会出现冲突。

实际上,这个地址是希望和 consumer-hello 这个服务匹配的,这个时候,只需要把配置文件改为 yml 格式就可以了。

忽略路径

默认情况下,zuul 注册到 eureka 上之后,eureka 上的所有注册服务都会被自动代理,如果不想给某个服务做代理,可以忽略该服务,配置如下:

# 忽略 provider 服务
zuul.ignored-services=provider 

上面这个配置表示忽略 provider 服务,此时就不会自动代理 provider 服务了。

也可以忽略某一类地址:

zuul.ignored-patterns=/**/hello/**

这个表示请求路径中如果包含 hello,则不做代理。

前缀

也可以给路由加前缀:

zuul.prefix=/he

这样,以后所有的请求地址自动多了前缀 /he

每天学习一点点,每天进步一点点。

posted @ 2020-08-09 12:01  爱吃西瓜的番茄酱  阅读(249)  评论(0编辑  收藏  举报