Spring Cloud 路由网关 ZUUL

Spring Cloud 路由网关 ZUUL

前言

在微服务架构中,需要几个基础的服务治理组件,包括服务注册与发现、服务消费、负载均衡、断路器、智能路由、配置管理等,由这几个基础组件相互协作,共同组建了一个简单的微服务系统。一个简答的微服务系统如下图:
2019060100542331.png

在Spring Cloud微服务系统中,一种常见的负载均衡方式是,客户端的请求首先经过负载均衡(Ngnix),到达服务网关(zuul集群),然后再到具体的服务。服务统一注册到高可用的服务注册中心集群,服务的所有的配置文件由配置服务管理(下一篇文章讲述),配置服务的配置文件放在git仓库,实现了配置的统一管理,方便开发人员随时改配置。

一、Zuul简介

Zuul的主要功能是路由转发和过滤器。路由功能是微服务的一部分,zuul默认和Ribbon结合实现了负载均衡的功能。从而客户端只需要统一的调用zuul网关的IP地址,再由网关进行路由转发,而不用因为各个服务不同而更改IP。比如/api/a转发到到a服务,/api/b转发到到b服务。

二、创建zuul工程

继续使用上一章节的工程,再原有工程中新建一个子module工程。创建过程不再赘述,创建好的pom文件内容如下:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>spring-cloud-demo</artifactId>
        <groupId>com.cxlsky.www</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>zuul</artifactId>

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
        </dependency>
    </dependencies>
</project>

在其入口主类加上注解@EnableZuulProxy,开启zuul的功能:

@SpringBootApplication(scanBasePackages = {"com.cxlsky"})
@EnableDiscoveryClient
@EnableZuulProxy
public class ZuulApplication {

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

增加springboot配置文件application.yml,内容如下:

server:
  port: 7000

spring:
  application:
    name: zuul

eureka:
  client:
    serviceUrl:
      defaultZone: http://10.1.81.33:8000/eureka/
zuul:
  routes:
    eureka-client-a:
      path: /client-a/**
      serviceId: eureka-client-a
    eureka-client-b:
      path: /client-b/**
      serviceId: eureka-client-b

以上的配置文件配置了两个路由,以/client-a/**开始的url转发到eureka-client-a服务,以/client-b/**开始的url转发到eureka-client-b服务。
现在我们把所有服务启动,然后用postman调用localhost:7000/client-b/hello/from/a可以得到以下结果:

this is eureka-client-b, port: 8002 and receive hello from: applicationName is: eureka-client-a, port is: 8001

用postman调用localhost:7000/client-a/hello可以得到以下结果:

applicationName is: eureka-client-a, port is: 8001

从上面的结果可以看出,zuul会根据我们配置的规则进行路由转发。

三、服务过滤

zuul不仅只是路由,并且还能过滤,做一些安全验证。如下:

package com.cxlsky;

import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;

/**
 * className ZuulFilter
 * description ZuulFilter
 *
 * @author Toby
 * @date 2019-6-12
 */
@Component
public class MyZuulFilter extends ZuulFilter {

    @Autowired
    private HttpServletRequest request;

    @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 ctx = RequestContext.getCurrentContext();
        ctx.addZuulRequestHeader("X-DOMAIN", request.getRemoteAddr());
        ctx.addZuulRequestHeader("USER-INFO", "{\"username\":\"cxl\"}");
        return null;
    }
}

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

pre:路由之前
routing:路由之时
post: 路由之后
error:发送错误调用

2、filterOrder:过滤的顺序
3、shouldFilter:这里可以写逻辑判断,是否要过滤,本文true,永远过滤。
4、run:过滤器的具体逻辑。可以增加自己需要的业务,这里增加了请求头信息,为后面的服务提供必要信息。