4

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

现在我也有一个具有以下配置的 Zuul 实现。

    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“预”过滤器。目标是根据标头值路由请求。

我已经能够拦截请求,但无法从过滤器中路由它。代码片段如下。运行代码后,请求仍会尝试转到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;
}

任何建议如何解决这个问题?

4

1 回答 1

5

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

首先,您的过滤器的顺序应该大于PreDecorationFilterDalston 版本中当前为 5 的顺序。(您需要检查您正在使用的版本中的值)。 PreDecorationFilter处理请求标头并将必要的信息填写到RequestContext. 这RequestContext将用于为您的请求定义实际 URL。requestURI是您需要更改的关键。在您的情况下,您可以根据标头附加或修改 requestURI。以下是您的预过滤器的片段。

@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 路线中的位置。此对象为所有请求共享。如果您仅针对特定请求更改它,则可能具有不同标头的其他请求可能会被路由到错误的位置。

其次,您要在ZuulRoute对象中设置 location 属性,如下所示。

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

最初位置属性值是您的服务 ID beta-root- 与您的配置。prefix, original如果您使用具有“http”或“https RibbonRoutingFilter will not work. Instead,SimpleRoutingHostFilter will process your request. It means that your not-modified requests will be handled byRibbonRoutingFilter and modified requests will be handled bySimpleHostRoutingFilter ”的特定 url 更改它。


更新:根据 Http Header 路由不同的主机

如果您想根据 http 标头路由到不同的主机,有几种方法可以做到这一点。

案例 1:如果您使用的是 Ribbon(和 RibbonRoutingFilter)

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

您可以在此处找到简要文档。

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

案例 2:如果您使用 SimpleHostRoutingFilter(不带功能区)

如果你指定url而不是serviceId在zuul的路由属性中,请求将由SimpleHostRoutingFilter 路由而不使用Ribbon。

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

RequestContext.getCurrentContext().getRouteHost();

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

  1. 制作您自己的自定义预过滤器,其顺序值介于 PreDecorationFilter 和 SimpleHostRoutingFilter 之间。
  2. 在您的过滤器中,检查路由主机。如果是任何已知主机,您要根据 HTTP 标头更改它,请根据 Http 标头更改路由主机RequestContext.getCurrentContext().setRouteHost

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

于 2017-05-03T02:55:54.430 回答