Spring Cloud 2021.X Eureka Cannot execute request on any known server

    最近用SpringCloud 2021搭建项目玩,遇到一个有点烦人的问题,卡了我一个小时,不是大问题,但值的记录一下,主要是思路和突破口的寻找。

    先说一下前因后果吧。找了一圈各类注册中心,发现符合我目前需求的依然是Eureka,出于安全原因,我需要开启Eureka Server的安全授权。个人觉得,无论是内网环境还是公网测试环境,都应该严格控制注册列表权限(这也是为什么我不用nacos的原因之一,nacos设置一堆东西,实在烦不胜烦,腾讯云提供的免费nacos竟然不支持设置安全相关的,只支持关闭公网访问,如果遇到坏蛋搞破坏……哈,扯远了)。所以在Eureka Server的pom.xml增加了以下依赖:

<dependency>
           <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-config</artifactId>
</dependency>

    然后调整eureka client端的url配置:

# 注册中心
eureka.client.register-with-eureka=true
eureka.client.service-url.defaultZone=http://user:user@localhost:8761/eureka/

    期望的结果是能够正常注册上去,然而控制台给我一堆错误:

com.netflix.discovery.shared.transport.TransportException: Cannot execute request on any known server
	at com.netflix.discovery.shared.transport.decorator.RetryableEurekaHttpClient.execute(RetryableEurekaHttpClient.java:112) ~[eureka-client-1.10.17.jar:1.10.17]
	at com.netflix.discovery.shared.transport.decorator.EurekaHttpClientDecorator.register(EurekaHttpClientDecorator.java:56) ~[eureka-client-1.10.17.jar:1.10.17]
	at com.netflix.discovery.shared.transport.decorator.EurekaHttpClientDecorator$1.execute(EurekaHttpClientDecorator.java:59) ~[eureka-client-1.10.17.jar:1.10.17]
	at com.netflix.discovery.shared.transport.decorator.SessionedEurekaHttpClient.execute(SessionedEurekaHttpClient.java:77) ~[eureka-client-1.10.17.jar:1.10.17]
	at com.netflix.discovery.shared.transport.decorator.EurekaHttpClientDecorator.register(EurekaHttpClientDecorator.java:56) ~[eureka-client-1.10.17.jar:1.10.17]
	at com.netflix.discovery.DiscoveryClient.register(DiscoveryClient.java:876) ~[eureka-client-1.10.17.jar:1.10.17]
	at com.netflix.discovery.InstanceInfoReplicator.run(InstanceInfoReplicator.java:121) ~[eureka-client-1.10.17.jar:1.10.17]
	at com.netflix.discovery.InstanceInfoReplicator$1.run(InstanceInfoReplicator.java:101) [eureka-client-1.10.17.jar:1.10.17]
	at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) [na:1.8.0_261]
	at java.util.concurrent.FutureTask.run$$$capture(FutureTask.java:266) [na:1.8.0_261]
	at java.util.concurrent.FutureTask.run(FutureTask.java) [na:1.8.0_261]
	at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180) [na:1.8.0_261]
	at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293) [na:1.8.0_261]
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [na:1.8.0_261]
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [na:1.8.0_261]
	at java.lang.Thread.run(Thread.java:748) [na:1.8.0_261]

    跟踪了一波源码发现用户和密码信息配置正确,Eureka Client底层源码(org.springframework.cloud.netflix.eureka.http.RestTemplateEurekaHttpClient):

@Override
	public EurekaHttpResponse<Void> register(InstanceInfo info) {
		String urlPath = serviceUrl + "apps/" + info.getAppName();

		HttpHeaders headers = new HttpHeaders();
		headers.add(HttpHeaders.ACCEPT_ENCODING, "gzip");
		headers.add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);

		ResponseEntity<Void> response = restTemplate.exchange(urlPath, HttpMethod.POST, new HttpEntity<>(info, headers),
				Void.class);

		return anEurekaHttpResponse(response.getStatusCodeValue()).headers(headersOf(response)).build();
	}

    通过Debug顺利拿到eureka-client请求eureka-server的相关信息,发现URL并没有问题,多次尝试后,排除Eureka-Client出问题。那么,只剩下Server端的问题了.

    观察Eureka-Server的控制台,发现并没有明显异常,随即把Eureka-Server的日志级别设置为debug级别,仔细观察控制台,发现有如下关键日志:

Invalid CSRF token found for

    啊哈,竟然是跨域了?早起版本并没有这个问题。顺利跟踪到日志输出的类:org.springframework.security.web.csrf.CsrfFilter

    问题范围再次缩小,spring-security的跨域问题,在eureka-server工程增加如下代码:

import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

/**
 * @author RippleChan
 * @date 2022/1/4 12:33 AM
 */
@Configuration
@EnableWebSecurity
public class EurekaSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable();
        http.authorizeRequests()
            .antMatchers("/login").permitAll()
            .anyRequest()
            .authenticated()
            .and()
            .httpBasic();
    }

}

    问题顺利解决。

    注意:这只是开发环境,所以直接禁用,如果是生产环境,建议根据实际需求配置跨域,避免不必要的安全问题。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章