将请求标头传递给Ribbon IRule密钥参数

ila*_*man 7 spring-mvc netflix spring-cloud

我有一个Spring Cloud应用程序,我正在自定义功能区客户端,如" 自定义功能区客户端"一节中所述,我的IRule如下所示:

public class HeadersRule extends AbstractLoadBalancerRule {

public HeadersRule () {
}

public HeadersRule(ILoadBalancer lb) {
    this();
    this.setLoadBalancer(lb);
}

public Server choose(ILoadBalancer lb, Object key) {

     //I want the key to contain the headers from the request so I can decide choose the server by one of the headers

    }
Run Code Online (Sandbox Code Playgroud)

我有一个休息控制器:

@RequestMapping("/")
public String hello(HttpServletRequest request, HttpServletResponse response) {

   //here I want to pass  the key parameter to ribbon

    return result;
}
Run Code Online (Sandbox Code Playgroud)

我想在我的IRule中按其中一个标题的值选择下一个服务器.如何将标题传递给我的自定义IRule关键参数?(通过RestTemplate或Feign,或者如果您有另一个使用Ribbon的选项...)

编辑可能的方向

在AbstractLoadBalancerAwareClient类中

public T executeWithLoadBalancer(final S request, final IClientConfig requestConfig) throws ClientException {
    RequestSpecificRetryHandler handler = getRequestSpecificRetryHandler(request, requestConfig);
    LoadBalancerCommand<T> command = LoadBalancerCommand.<T>builder()
            .withLoadBalancerContext(this)
            .withRetryHandler(handler)
            .withLoadBalancerURI(request.getUri())
            .build();
Run Code Online (Sandbox Code Playgroud)

构建LoadBalancer命令并省略:

.withServerLocator(request)
Run Code Online (Sandbox Code Playgroud)

本来可以做到的!我可以从配置中覆盖此方法,在我可以配置的Spring RibbonClientConfiguration类中:

@Bean
@Lazy
@ConditionalOnMissingBean
public RestClient ribbonRestClient(IClientConfig config, ILoadBalancer loadBalancer) {
    RestClient client = new OverrideRestClient(config);
    client.setLoadBalancer(loadBalancer);
    Monitors.registerObject("Client_" + this.name, client);
    return client;
}
Run Code Online (Sandbox Code Playgroud)

问题是名称不起作用:

@Value("${ribbon.client.name}")
private String name = "client";
Run Code Online (Sandbox Code Playgroud)

似乎应该使用此名称进行一些配置,因为我看到我的loadbalancer服务器列表由于某种原因总是空的,如果有人知道我应该如何配置此属性我相信它可以解决问题...

Uzi*_*Uzi 4

我对您的方法进行了一些修改以使其正常工作:除了使用 RibbonRestClient bean 之外,您还需要提供 RibbonServerList bean。但不要采用 RibbonClientConfiguration 中定义的使用 ConfigurationBasedServerList 的 bean。这就是你得到空列表的原因。您可以定义服务器列表您的配置,或者,如果您更喜欢使用 eureka,则可以从 EurekaRibbonClientConfiguration 获取 bean:

@Bean
@ConditionalOnMissingBean
public ServerList<?> ribbonServerList(IClientConfig config) {
    DiscoveryEnabledNIWSServerList discoveryServerList = new DiscoveryEnabledNIWSServerList(
            config);
    DomainExtractingServerList serverList = new DomainExtractingServerList(
            discoveryServerList, config, this.approximateZoneFromHostname);
    return serverList;
}
Run Code Online (Sandbox Code Playgroud)

这将动态填充您的服务器列表。除此之外,请确保您用来覆盖 RibbonRestClientBean 的配置文件不会被自动扫描。这就是造成的

@Value("${ribbon.client.name}")
private String name = "client";
Run Code Online (Sandbox Code Playgroud)

尝试在应用程序加载时填充。要么将配置放在与主应用程序类不同的包中,要么将其排除在扫描之外

最后,不要忘记将 @RibbonClient / @RibbonClients 添加到您的主类中以指向覆盖的配置

@RibbonClients(defaultConfiguration = {my.non.autoScanned.MyRibbonClientConfiguration.class} ) 
@SpringBootApplication()
public class MyApp {
Run Code Online (Sandbox Code Playgroud)