使用Eureka的HTTP请求未正确填充端口问题排查
我通过docker-compose在Docker容器中运行多个服务,尝试从一个服务向另一个服务发起HTTP请求时失败——请求始终使用80端口,而非Eureka中注册的端口。
遍历已发现的应用时,能正确获取到注册信息:
List<Application> applications = discoveryClient.getApplications().getRegisteredApplications(); for (Application application : applications) { List<InstanceInfo> applicationsInstances = application.getInstances(); for (InstanceInfo applicationsInstance : applicationsInstances) { String name = applicationsInstance.getAppName(); String url = applicationsInstance.getHomePageUrl(); System.out.println(name + ": " + url); } }
输出结果正确:
IDENTITY-SERVICE: http://172.20.0.3:10103/
但使用WebClient发起如下请求时:
return webClientBuilder .build() .post() .uri("http://identity-service/api/auth/validate", uriBuilder -> uriBuilder.queryParam("token", "xyz").build()) .retrieve() .bodyToMono(ValidationResponseDTO.class);
抛出异常,显示请求调用的是80端口:
org.springframework.web.reactive.function.client.WebClientRequestException: finishConnect(..) failed: Connection refused: identity-service/172.20.0.3:80
手动指定端口(即http://identity-service:10103/api/auth/validate)时,请求能正常执行。请问为何请求未使用Eureka中注册的端口?
问题的核心是你当前的WebClient没有集成Spring Cloud的负载均衡能力,直接用服务名发起请求时,WebClient会将其视为普通域名,通过Docker内部DNS解析到容器IP后,默认使用HTTP的80端口发起请求,而非从Eureka获取注册的端口。
解决步骤:
引入负载均衡依赖
在你的pom.xml(Maven)或build.gradle(Gradle)中添加Spring Cloud LoadBalancer依赖:
Maven示例:<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-loadbalancer</artifactId> </dependency>Gradle示例:
implementation 'org.springframework.cloud:spring-cloud-starter-loadbalancer'配置带负载均衡的WebClient.Builder
在配置类中声明带有@LoadBalanced注解的WebClient.BuilderBean:@Configuration public class WebClientConfig { @Bean @LoadBalanced public WebClient.Builder loadBalancedWebClientBuilder() { return WebClient.builder(); } }修改请求URI的写法
使用lb://前缀指定服务名,让负载均衡组件介入,自动从Eureka获取实例的正确端口:return webClientBuilder // 这里注入的是带@LoadBalanced的builder .build() .post() .uri("lb://identity-service/api/auth/validate", uriBuilder -> uriBuilder.queryParam("token", "xyz").build()) .retrieve() .bodyToMono(ValidationResponseDTO.class);
这样调整后,WebClient会通过Spring Cloud LoadBalancer从Eureka拉取identity-service的注册实例信息,自动使用正确的端口发起请求,无需手动指定端口。
内容的提问来源于stack exchange,提问作者Benedikt J Schlegel

