如何基于HTTP方法制作Zuul动态路由并通过'serviceId'解析目标主机?

时间:2017-12-17 15:26:19

标签: spring spring-cloud netflix-zuul spring-cloud-netflix

如何基于 HTTP方法(GET / POST / PUT ...)进行Zuul动态路由? 例如,当您需要将 POST 请求路由到不同主机而不是“ zuul.routes。* ”中描述的默认请求时...

zuul:
  routes:
    first-service:
      path: /first/**
      serviceId: first-service
      stripPrefix: false

    second-service:
      path: /second/**
      serviceId: second-service
      stripPrefix: false

即。当我们请求' GET / first '时,Zuul会将请求路由到' first-service ',但是如果我们请求' POST / first '然后Zuul将请求路由到'第二服务'。

2 个答案:

答案 0 :(得分:5)

要实施基于HTTP方法的动态路由,我们可以创建自定义“ route ”类型ZuulFilter并通过DiscoveryClient解析'serviceId'。例如:

@Component
public class PostFilter extends ZuulFilter {

    private static final String REQUEST_PATH = "/first";
    private static final String TARGET_SERVICE = "second-service";
    private static final String HTTP_METHOD = "POST";

    private final DiscoveryClient discoveryClient;

    public PostOrdersFilter(DiscoveryClient discoveryClient) {
        this.discoveryClient = discoveryClient;
    }

    @Override
    public String filterType() {
        return "route";
    }

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

    @Override
    public boolean shouldFilter() {
        RequestContext context = RequestContext.getCurrentContext();
        HttpServletRequest request = context.getRequest();
        String method = request.getMethod();
        String requestURI = request.getRequestURI();
        return HTTP_METHOD.equalsIgnoreCase(method) && requestURI.startsWith(REQUEST_PATH);
    }

    @Override
    public Object run() {

        RequestContext context = RequestContext.getCurrentContext();
        List<ServiceInstance> instances = discoveryClient.getInstances(TARGET_SERVICE);
        try {
            if (instances != null && instances.size() > 0) {
                context.setRouteHost(instances.get(0).getUri().toURL());
            } else {
                throw new IllegalStateException("Target service instance not found!");
            }
        } catch (Exception e) {
            throw new IllegalArgumentException("Couldn't get service URL!", e);
        }
        return null;
    }
}

答案 1 :(得分:0)

@Cepr0's solution是正确的。在这里,我提出一种更简单的方法(不进行服务发现)。假设您有该路线:

zuul:
    routes:
        first:
            path: /first/**
            # No need for service id or url

然后,您只需设置请求上下文的位置即可在“ 路线”类型过滤器中路由“ /第一”路线的请求。

@Component
    public class RoutingFilter extends ZuulFilter {

    @Override
    public String filterType() {
        return ROUTE_TYPE;
    }

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

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

    @Override
    public Object run() throws ZuulException {
        /* Routing logic goes here */
        URL location = getRightLocationForRequest();
        ctx.setRouteHost(location);

        return null;
    }
}