在Spring Cloud Netflix Zuul中以编程方式设置路线 [英] Setting the route programmatically in Spring Cloud Netflix Zuul

查看:107
本文介绍了在Spring Cloud Netflix Zuul中以编程方式设置路线的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我创建了两个AWS Beanstalk环境,每个环境都有自己的应用程序版本.这些环境的网址为 https://beta.myserver.com/v1073 https://beta.myserver.com/v1084 .这些网址指向负载均衡器.

I have created two AWS Beanstalk envs, each with their own version of the applications. The urls for these envs are https://beta.myserver.com/v1073 and https://beta.myserver.com/v1084. These urls point to the load balancer.

现在,我还有一个Zuul实现,该实现具有以下配置.

Now I also have a Zuul implementation that have the following configurations.

    zuul:
      routes:
        beta:
          path: /api/**
          serviceId: beta-root
          strip-prefix: false
          sensitive-headers: Cookie,Set-Cookie

    ribbon:
      eureka:
        enabled: false

    hystrix:
      command:
        default:
          execution:
            isolation:
              thread:
                timeoutInMilliseconds: 5000

    beta-root:
      ribbon:
        listOfServers: https://beta.myserver.com

对我的应用程序的请求必须具有版本标头.我有一个Zuul前置"过滤器,用于检查此标头值.目标是根据标头值路由请求.

Request for my application must have a version header. I have a Zuul "pre" filter that inspect this header value. The goal is to route the request based on the header value.

我已经能够截获该请求,但无法将其从过滤器发送出去.该代码段如下.运行代码后,请求仍然尝试尝试 https://beta.myserver.com/api/ ...

I have been able to intercept the request, but have not been able to route it from the filter. The code snippet is below. After running the code the request still tries to go https://beta.myserver.com/api/...

@Override
public Object run() {
    /* Logic to get version header etc */

    /* Set the new route */
    Map<String, ZuulRoute> routes = zuulProps.getRoutes();
    ZuulRoute currentRoute = routes.get("beta-root");
    currentRoute.setLocation("https://beta.myserver.com/v1073");

    /* Refresh the route */
    routeLocator.getRoutes();

    logger.warn("Current Route:" + currentRoute.getLocation());
    return null;
}

任何建议如何解决此问题?

Any suggestion how to resolve this issue?

推荐答案

您真正需要做的是更改requestURI,而不是您的服务器位置.您可以像下面这样轻松地做到这一点.

What you really need to do is that changing requestURI, not server location in your case. You can easily do that like below.

首先,您的过滤器顺序应大于Dalston版本中当前为5的PreDecorationFilter顺序. (您需要检查所使用发行版中的值). PreDecorationFilter处理请求标头,并将必要的信息填充到RequestContext中.此RequestContext将用于定义您的请求的实际URL. requestURI是您需要更改的密钥.在这种情况下,您可以基于标头附加或修改requestURI.以下是您的前置过滤器的代码段.

First, your filter's order should be bigger than PreDecorationFilter's order that is currently 5 in Dalston release. (You need to check the value from the release you're using). PreDecorationFilter processes request header and fill necessary info into RequestContext. And this RequestContext will be used to define actual URL for your request. requestURI is the key that you need to change. In you case, you can append or modify requestURI based on headers. The below is snippet for your pre-filter.

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

@Override
public Object run() {
    RequestContext ctx = RequestContext.getCurrentContext();
    // override request URI
    ctx.set("requestURI", "/v1073" + ctx.get("requestURI"));
    return null;
}

您的原始实现似乎有一些问题.首先,您要更改ZuulProperties路线中的位置.所有请求均共享该对象.如果仅针对特定请求进行更改,则可能具有不同标头的其他请求可能会被路由到错误的位置.

Your original implementation seems to have some problems. First, you're trying to change location in ZuulProperties route. This object is shared for all requests. If you change it just for a specific request, other request that may have different headers could be routed to wrong location.

第二,您要在ZuulRoute对象中设置位置属性,如下所示.

Second, you're setting location property in ZuulRoute object like below.

currentRoute.setLocation("https://beta.myserver.com/v1073");

最初的位置属性值是您的服务ID-beta-root-与您的配置一起.如果您使用具有'http'或'https prefix, original RibbonRoutingFilter will not work. Instead, SimpleRoutingHostFilter will process your request. It means that your not-modified requests will be handled by RibbonRoutingFilter and modified requests will be handled by SimpleHostRoutingFilter`的特定网址进行更改.

Originally location property value is your service-id -beta-root - with your configuration. If you change it with a specific url that has 'http' or 'httpsprefix, originalRibbonRoutingFilterwill not work. Instead,SimpleRoutingHostFilterwill process your request. It means that your not-modified requests will be handled byRibbonRoutingFilterand modified requests will be handled bySimpleHostRoutingFilter`.

更新:基于Http标头路由不同的主机

如果要基于http标头路由到其他主机,则有几种方法可以做到这一点.

If you want to route to different hosts based on http headers, there are several ways to do that.

情况1:如果您正在使用Ribbon(和RibbonRoutingFilter)

以下功能仅适用于 Edgware.SR1 和更高版本.在Eddware.SR1中,您可以在RequestContext中放入名为FilterConstants.LOAD_BALANCER_KEY的负载均衡器的指定值.该值将传递到功能区负载平衡器中.您可以将所需的任何值(任何对象)放入预过滤器中.如果要基于特殊的http标头更改路由,则可以在自定义预过滤器中执行此操作. 然后为Ribbon定义自己的IRule实现.LOAD_BALANCER_KEY将提供给您的IRule实现.因此,您可以根据设置的LOAD_BALANCER_KEY值,从Ribbon具有的服务器列表中选择特定的服务器.

The following feature only works on Edgware.SR1 and later version. From Eddware.SR1, you can put specify value for loadbalancer called FilterConstants.LOAD_BALANCER_KEY in RequestContext. This value will be passed into Ribbon load balancer. You can put any value(any object) that you want in your prefilter. If you want to change route based on a special http header, you can do that in your custom prefilter. And then define your own IRule implementation for Ribbon.LOAD_BALANCER_KEY will be given to your IRule implementation. Therefore you can choose the specific server from the list of server that Ribbon has based on the value of LOAD_BALANCER_KEY that you set.

您可以找到简短的文档

You can find brief documentation here.

您可以在 PR中的测试用例中找到示例代码. (RibbonRoutingFilterLoadBalancerKeyIntegrationTests.java)

You can find sample code from the test case in PR. (RibbonRoutingFilterLoadBalancerKeyIntegrationTests.java)

情况2:如果您使用的是SimpleHostRoutingFilter(无功能区)

如果在zuul的路由属性中指定url而不是serviceId,则请求将由SimpleHostRoutingFilter路由而不使用功能区.

If you specify url instead of serviceId in zuul's route properties, the request will be routed by SimpleHostRoutingFilter without Ribbon.

SimpleHostRoutingFilter仅通过以下代码使用主机地址

SimpleHostRoutingFilter just use the host address by the below code

RequestContext.getCurrentContext().getRouteHost();

此值由PreDecorationFilter设置.因此,您可以在预过滤器中更改此信息.

This value is set by PreDecorationFilter. So you can change this info in your prefilter.

  1. 制作自己的自定义预过滤器,该过滤器的顺序介于PreDecorationFilter和SimpleHostRoutingFilter之间.
  2. 在过滤器内部,检查路由主机.如果您要基于HTTP标头更改任何已知主机,请通过基于HTTP标头的RequestContext.getCurrentContext().setRouteHost更改路由主机.
  1. Make your own custom prefilter that has the order value between PreDecorationFilter's and SimpleHostRoutingFilter's.
  2. Inside your filter, check route host. If it is any known host that you want to change it based on HTTP header, change the route host via RequestContext.getCurrentContext().setRouteHost based on Http Header.

在第二种方法的情况下,我没有尝试自己做.我认为这只是理论上的解决方案. 第二种方法的问题是它正在使用SimpleHostRoutingFilter. SimpleHostRoutingFilter不会对请求发出任何HystrixCommand,因此您不能使用Zuul内部Hystrix提供的任何断路器功能.如果您使用的是Edgware版本,则我认为第一种方法会更好.

In case of the second approach, I didn't try to do that by myself. It's just theoretical solution that I think. The problem of the second approach is that it is using SimpleHostRoutingFilter. SimpleHostRoutingFilter doesn't make any HystrixCommand for the request, so you can't use any circuit breaker features that is provided by Hystrix inside Zuul. If you are using Edgware release, the first approach is better as I think.

这篇关于在Spring Cloud Netflix Zuul中以编程方式设置路线的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆