简体   繁体   English

如何将自定义 restTemplate 实例添加到 RestTemplateEurekaHttpClient

[英]How to add custom restTemplate istance into RestTemplateEurekaHttpClient

My intention is to replace Jersey implementation of eureka client with the one provided with a Spring restTemplate.我的目的是用 Spring restTemplate 提供的那个替换 eureka 客户端的 Jersey 实现。

Then, replace the standard implementation of the rest template with one that trust all certificates (i know it's not raccomanded but it doesn't matter right now) in order to register my service to a secure (https) eureka server.然后,将 rest 模板的标准实现替换为信任所有证书的模板(我知道它不是 raccomanded 但现在无关紧要),以便将我的服务注册到安全 (https) eureka 服务器。

I'm using Spring boot 2.2.1-RELEASE and Spring cloud Hoxton.RC2.我正在使用 Spring boot 2.2.1-RELEASE 和 Spring cloud Hoxton.RC2。

According to the official documentation in a spring boot project declaring eureka client this way根据 spring boot 项目中的官方文档,以这种方式声明 eureka 客户端

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>com.sun.jersey</groupId>
                    <artifactId>jersey-client</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>com.sun.jersey</groupId>
                    <artifactId>jersey-core</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>com.sun.jersey.contribs</groupId>
                    <artifactId>jersey-apache-client4</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

force the application to use a RestTemplate as the Eureka Client.强制应用程序使用 RestTemplate 作为 Eureka 客户端。

I Already have a custom RestTemplate implementation in my application, lets call it RestTemplateImpl , i'll omit implementation code cause it's irrelevant.我的应用程序中已经有一个自定义 RestTemplate 实现,我们称之为RestTemplateImpl ,我将省略实现代码,因为它无关紧要。

When the application start i was expectin my RestTemplateImpl to be injected as the deafault eureka client implementation, but it wasn't.当应用程序启动时,我希望我的 RestTemplateImpl 作为默认的 eureka 客户端实现被注入,但事实并非如此。

As the exception says正如例外所说

org.springframework.web.client.ResourceAccessException: I/O error on POST request for "https://localhost:3000/eureka/apps/MY-API": java.security.cert.CertificateException: No name matching localhost found; nested exception is javax.net.ssl.SSLHandshakeException: java.security.cert.CertificateException: No name matching localhost found
    at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:751) ~[spring-web-5.2.1.RELEASE.jar:5.2.1.RELEASE]
    at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:677) ~[spring-web-5.2.1.RELEASE.jar:5.2.1.RELEASE]
    at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:586) ~[spring-web-5.2.1.RELEASE.jar:5.2.1.RELEASE]
    at org.springframework.cloud.netflix.eureka.http.RestTemplateEurekaHttpClient.register(RestTemplateEurekaHttpClient.java:73) ~[spring-cloud-netflix-eureka-client-2.2.0.RC2.jar:2.2.0.RC2]
    at com.netflix.discovery.shared.transport.decorator.EurekaHttpClientDecorator$1.execute(EurekaHttpClientDecorator.java:59) [eureka-client-1.9.13.jar:1.9.13]
    at com.netflix.discovery.shared.transport.decorator.RedirectingEurekaHttpClient.executeOnNewServer(RedirectingEurekaHttpClient.java:118) ~[eureka-client-1.9.13.jar:1.9.13]
    at com.netflix.discovery.shared.transport.decorator.RedirectingEurekaHttpClient.execute(RedirectingEurekaHttpClient.java:79) ~[eureka-client-1.9.13.jar:1.9.13]
    at com.netflix.discovery.shared.transport.decorator.EurekaHttpClientDecorator.register(EurekaHttpClientDecorator.java:56) [eureka-client-1.9.13.jar:1.9.13]
    at com.netflix.discovery.shared.transport.decorator.EurekaHttpClientDecorator$1.execute(EurekaHttpClientDecorator.java:59) [eureka-client-1.9.13.jar:1.9.13]
    at com.netflix.discovery.shared.transport.decorator.RetryableEurekaHttpClient.execute(RetryableEurekaHttpClient.java:120) [eureka-client-1.9.13.jar:1.9.13]
    at com.netflix.discovery.shared.transport.decorator.EurekaHttpClientDecorator.register(EurekaHttpClientDecorator.java:56) [eureka-client-1.9.13.jar:1.9.13]
    at com.netflix.discovery.shared.transport.decorator.EurekaHttpClientDecorator$1.execute(EurekaHttpClientDecorator.java:59) [eureka-client-1.9.13.jar:1.9.13]
    at com.netflix.discovery.shared.transport.decorator.SessionedEurekaHttpClient.execute(SessionedEurekaHttpClient.java:77) [eureka-client-1.9.13.jar:1.9.13]
    at com.netflix.discovery.shared.transport.decorator.EurekaHttpClientDecorator.register(EurekaHttpClientDecorator.java:56) [eureka-client-1.9.13.jar:1.9.13]
    at com.netflix.discovery.DiscoveryClient.register(DiscoveryClient.java:847) [eureka-client-1.9.13.jar:1.9.13]
    at com.netflix.discovery.InstanceInfoReplicator.run(InstanceInfoReplicator.java:121) [eureka-client-1.9.13.jar:1.9.13]
    at com.netflix.discovery.InstanceInfoReplicator$1.run(InstanceInfoReplicator.java:101) [eureka-client-1.9.13.jar:1.9.13]
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) [na:1.8.0_212]
    at java.util.concurrent.FutureTask.run(FutureTask.java:266) [na:1.8.0_212]
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180) [na:1.8.0_212]
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293) [na:1.8.0_212]
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [na:1.8.0_212]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [na:1.8.0_212]
    at java.lang.Thread.run(Thread.java:748) [na:1.8.0_212]

Spring uses a RestTemplateEurekaHttpClient . Spring 使用RestTemplateEurekaHttpClient

Looking into the source code i found no way to inject my RestTemplateImpl in favor of the one existing.查看源代码,我发现无法注入我的RestTemplateImpl以支持现有的。

public class RestTemplateTransportClientFactory implements TransportClientFactory {

    @Override
    public EurekaHttpClient newClient(EurekaEndpoint serviceUrl) {
        return new RestTemplateEurekaHttpClient(restTemplate(serviceUrl.getServiceUrl()),
                serviceUrl.getServiceUrl());
    }

    private RestTemplate restTemplate(String serviceUrl) {
        RestTemplate restTemplate = new RestTemplate();
        try {
            URI serviceURI = new URI(serviceUrl);
            if (serviceURI.getUserInfo() != null) {
                String[] credentials = serviceURI.getUserInfo().split(":");
                if (credentials.length == 2) {
                    restTemplate.getInterceptors().add(new BasicAuthorizationInterceptor(
                            credentials[0], credentials[1]));
                }
            }
        }
        catch (URISyntaxException ignore) {

        }

        restTemplate.getMessageConverters().add(0, mappingJacksonHttpMessageConverter());
        restTemplate.setErrorHandler(new ErrorHandler());

        return restTemplate;
    }

    .....

Please...help me solve this problem...请...帮我解决这个问题...

This can be done in the following way, though it's not recommended for production use这可以通过以下方式完成,但不建议用于生产用途

have your custom RestTemplateTransportClientFactory implementation, for example use the following code, (used eureka-client-1.9.17 and spring 2.2.2.RELEASE)有您的自定义 RestTemplateTransportClientFactory 实现,例如使用以下代码,(使用 eureka-client-1.9.17 和 spring 2.2.2.RELEASE)

@Bean
public RestTemplateDiscoveryClientOptionalArgs discoveryClientOptionalArgs() throws Exception {
    RestTemplateDiscoveryClientOptionalArgs args = new RestTemplateDiscoveryClientOptionalArgs();
    args.setHostnameVerifier(NoopHostnameVerifier.INSTANCE);
    args.setTransportClientFactories(new CustomRestTemplateTransportClientFactories());
    return args;
}

public class CustomRestTemplateTransportClientFactories extends RestTemplateTransportClientFactories {

    @Override
    public TransportClientFactory newTransportClientFactory(final EurekaClientConfig clientConfig,
            final Collection<Void> additionalFilters, final InstanceInfo myInstanceInfo,
            final Optional<SSLContext> sslContext, final Optional<HostnameVerifier> hostnameVerifier) {
        return new CustomRestTemplateTransportClientFactory();
    }
}

public class CustomRestTemplateTransportClientFactory extends RestTemplateTransportClientFactory {

    @Override
    public EurekaHttpClient newClient(EurekaEndpoint serviceUrl) {
        try {
            return new RestTemplateEurekaHttpClient(restTemplate(serviceUrl.getServiceUrl()),
                    serviceUrl.getServiceUrl());
        }
        catch (HttpClientException e) {
            e.printStackTrace();
        }
        return null;
    }

    private RestTemplate restTemplate(String serviceUrl) throws HttpClientException {
        /*
         * Inject your custom rest template
         */
        RestTemplate restTemplate = restTemplateConfig.restTemplate(null);
        try {
            URI serviceURI = new URI(serviceUrl);
            if (serviceURI.getUserInfo() != null) {
                String[] credentials = serviceURI.getUserInfo().split(":");
                if (credentials.length == 2) {
                    restTemplate.getInterceptors()
                            .add(new BasicAuthenticationInterceptor(credentials[0], credentials[1]));
                }
            }
        }
        catch (URISyntaxException ignore) {

        }

        restTemplate.getMessageConverters().add(0, mappingJacksonHttpMessageConverter());
        restTemplate.setErrorHandler(new ErrorHandler());

        return restTemplate;
    }
}

class ErrorHandler extends DefaultResponseErrorHandler {

    @Override
    protected boolean hasError(HttpStatus statusCode) {
        /**
         * When the Eureka server restarts and a client tries to sent a
         * heartbeat the server will respond with a 404. By default
         * RestTemplate will throw an exception in this case. What we want
         * is to return the 404 to the upstream code so it will send another
         * registration request to the server.
         */
        if (statusCode.is4xxClientError()) {
            return false;
        }
        return super.hasError(statusCode);
    }

}

Hope this will be helpful.希望这会有所帮助。 Thanks.谢谢。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何将标题添加到 RestTemplate - How to add the header into RestTemplate 将我的自定义 http 标头添加到 Spring RestTemplate 请求/扩展 RestTemplate - Add my custom http header to Spring RestTemplate request / extend RestTemplate 如何将opentrace拦截器添加到restTemplate? - How to add opentrace interceptor to restTemplate? 如何将Spring Cache Redis与自定义RestTemplate一起使用? - How to use Spring Cache Redis with a custom RestTemplate? 如何设置自定义OAuth2RestTemplate或自定义OAuth2ProtectedResourceDetails? - How to set custom OAuth2RestTemplate or custom OAuth2ProtectedResourceDetails? 发送自定义标头 RestTemplate - Send custom headers RestTemplate 如何通过RestTemplate在头文件中使用自定义参数发送POST请求 - How to send POST request through RestTemplate with custom parameter in header 使用 SimpleClientHttpRequestFactory 时,如何使自定义 RestTemplate 使用标准 Spring Boots 的 Prometheus RestTemplate 指标进行检测? - How to make custom RestTemplate to instrument with standard Spring Boots' Prometheus RestTemplate metrics when using SimpleClientHttpRequestFactory? RestTemplate与自定义ConnectionPool? - RestTemplate with custom ConnectionPool? 如何为 Spring 中的每个客户端配置和构建自定义 RestTemplate? - How to configure and build a custom RestTemplate for each client in Spring?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM