SpringCloud动态路由--Zuul

博客同步至GitPress:https://gitpress.io/@yangshijie/spring_cloud_zuul

示例代码已上传Github: https://github.com/yshijie/spring_cloud_demo

Zuul组件简介

Zuul组件主要是用来做动态路由转发和请求拦截过滤等;

在客户端访问服务端时,经常会有一些通过验证用户的token或者请求头之类的去判断并且指定具体访问哪些数据服务,例如不同组织机构的用户通过请求的token的不同被服务端指定分发到不同的数据中心去查询对应的数据;

以及在客户端请求服务端时,服务端拦截客户端请求,可以对请求做一些预处理等操作;

在SpringCloud工程中,创建了两个数据服务datacenter-a和datacenter-b,以及一个注册服务,一个分发服务,这个分发服务就是用来指定路由去访问具体哪个数据中心的数据;

核心类

Zuul组件的核心类是ZuulFilter,通过自定义过滤类继承该类,并重写指定方法进行请求的拦截处理;

public class MyFilter extends ZuulFilter {

    Override
    public String filterType() {
        return "pre";
    }

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

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

    @Override
    public Object run() {
        return null;
    }
}

filterType方法:指定在什么地方进行拦截,可以使是请求前/后,发生错误时等;

pre:在路由转发之前作用;
routing:在路由时起作用;
post:在返回结果时作用;
error:在整个路由阶段,出现异常时作用;

filterOder方法:拦截的优先级,0表示最大;

shouldFliter方法:是否拦截,可以通过一些逻辑判断是否需要进行拦截;

run方法:执行具体的拦截操作;

添加依赖

在需要进行动态路由转发的服务(即分发服务)的pom.xml文件中加入依赖:

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

动态路由转发

通过请求地址不同将服务指向不同的子服务,例如,服务集群中,A服务用于存储用户信息,B服务用于存储相关的商品信息,在请求是通过路径设定user/goods将查询指向不同的服务;

配置转发信息

启动类注解

在需要进行动态路由转发的服务(即分发服务)的启动类上配置@EnableZuulProxy注解:

@SpringBootApplication
@EnableEurekaClient
@EnableZuulProxy
public class DispatchServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(DispatchServerApplication.class, args);
    }
}

application.yml文件配置

在分发服务的application.yml文件中配置需要转发的逻辑和转发的对应服务地址:

spring:
    application:
        name: dispatch-server
server:
    port: 8760
eureka:
    client:
        service-url:
            defaultZone: http://localhost:8761/eureka/
zuul:
    retryable: false
    routes:
        data-a:
            path: /user/**
            serviceId: data-server-a
        data-b:
            path: /goods/**
            serviceId: data-server-b

请求测试

通过网关访问:

http://localhost:8760/alarm/aaa/getData
http://localhost:8760/goods/aaa/getData

此时根据上面yml中的配置,第一个请求将自动转发到data-server-a这个数据服务,第二个请求将自动转发到data-server-b这个数据服务;

请求拦截过滤

4中的方法是一个比较简单直白的做法,也可以对请求进行拦截判断,通过请求的不同参数、或者请求头信息等,将客户端请求指向不同的服务;

yml配置路由信息

zuul:
    routes:
        data-a:
            path: /**
            serviceId: service-datacenter-a
        data-b:
            path:/**
            serviceId:service-datacenter-b

过滤请求

@Value("${zuul.routes.data-a.serviceId}")
private String aa;

@Value("${zuul.routes.data-b.serviceId}")
private String bb;

@Override
public Object run() throws ZuulException {
    RequestContext ctx = RequestContext.getCurrentContext();
    HttpServletRequest request = ctx.getRequest();
    HttpServletResponse response = ctx.getResponse();

    String userType = request.getParameter("userType");
    String serviceId = null;
    try {
        if (userType != null) {
            if (userType.equals("A")) {
                serviceId = aa;
            } else if (userType.equals("B")) {
                serviceId = bb;
            }
        } else {
            serviceId = "xxx";
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
    if (serviceId == null) {
        //服务查询失败 不再路由直接返回
        response.setHeader("Content-Type", "application/json;charset=UTF-8");
        ctx.setSendZuulResponse(false);
        ctx.setResponseBody("Error: No service");
    } else {
        //转发请求
        log.info("--->>> Forward to service :" + serviceId);
        ctx.set("serviceId", serviceId);
    }
    return null;
}

在该类上添加@Configuration注解表明是个配置类;

以上做法中,访问的地址为同一个,但是根据传入的参数不同,利用Zuul拦截请求,将请求重新定义定指定转发到不同的子服务中;

请求测试

两个子服务分别访问地址为:

A:http://localhost:8763/aaa/getData?userType=""
B:http://localhost:8762/aaa/getData?userType=""

通过网关访问时,请求http://localhost:8760/aaa/getData?userType="",当参数传入A时,请求转发到A服务,当传输传入B时,转发到B服务;

这样对用户来说是无感觉的,可以将判断标准定为请求的token等来作为转发的判断条件等;

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章