spring - spring boot 2 + feign + eureka 客户端不会将服务名称解析为 URL
问题描述
我正在尝试使用 spring-cloud (Finchley.SR1) 的 spring-boot (2.0.5) 并尝试使用 Eureka 作为发现服务器和 Feign/Ribbon 作为客户端来设置两个服务之间的通信。设置非常简单(尽管我尝试过的各种事情和其他答案有点混乱):
尤里卡的application.yml
spring:
application:
name: eureka-service
server:
port: 8761
eureka:
instance:
hostname: localhost
preferIpAddress: true
client:
registerWithEureka: false
fetchRegistry: false
serviceUrl:
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka
第二个服务的 bootstrap.yml
spring:
application:
name: secondservice
eureka:
instance:
hostname: ${spring.application.name}
preferIpAddress: true
instanceId: ${spring.application.name}:${spring.application.instance_id:${random.value}}
statusPageUrlPath: ${server.servlet.context-path}/actuator/info
healthCheckUrlPath: ${server.servlet.context-path}/actuator/health
leaseRenewalIntervalInSeconds: 15
leaseExpirationDurationInSeconds: 45
metadata-map:
server.servlet.context-path: ${server.servlet.context-path}
client:
enabled: true
serviceUrl:
defaultZone: http://localhost:8761/eureka
我的测试/模板服务的 bootstrap.yml
spring:
application:
name: templateservice
eureka:
instance:
hostname: ${spring.application.name}
preferIpAddress: true
instanceId: ${spring.application.name}:${spring.application.instance_id:${random.value}}
statusPageUrlPath: ${server.servlet.context-path}/actuator/info
healthCheckUrlPath: ${server.servlet.context-path}/actuator/health
leaseRenewalIntervalInSeconds: 15
leaseExpirationDurationInSeconds: 45
metadata-map:
server.servlet.context-path: ${server.servlet.context-path}
client:
enabled: true
serviceUrl:
defaultZone: http://localhost:8761/eureka
logging:
level:
com...MessageServiceClient: DEBUG
我的Feign 客户
@FeignClient(name = "secondservice", configuration = FeignConfig.class)
public interface MessageServiceClient {
@RequestMapping(method = RequestMethod.GET, value = "/dummy")
public String getMessage();
}
我的服务类:
@Autowired MessageServiceClient messageServiceClient;
@Autowired private LoadBalancerClient loadBalancer;
public String getDummyMessage() {
ServiceInstance instance = loadBalancer.choose("secondservice");
URI secondServiceUri = URI.create(String.format("http://%s:%s", instance.getHost(), instance.getPort()));
System.out.println(secondServiceUri); // logs http://192.168.0.205:8090, check log below
return messageServiceClient.getMessage(); // throws 404??
}
在 FeignConfig 中,唯一要做的就是将日志级别设置为 FULL。日志如下所示:
2018-10-08 11:14:59.511 INFO [templateservice,,,] 16801 --- [onPool-worker-2] s.c.a.AnnotationConfigApplicationContext : Refreshing SpringClientFactory-secondservice: startup date [Mon Oct 08 11:14:59 IST 2018]; parent: org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@451f35ad
2018-10-08 11:14:59.683 INFO [templateservice,,,] 16801 --- [onPool-worker-2] f.a.AutowiredAnnotationBeanPostProcessor : JSR-330 'javax.inject.Inject' annotation found and supported for autowiring
2018-10-08 11:15:00.042 INFO [templateservice,,,] 16801 --- [onPool-worker-2] c.netflix.config.ChainedDynamicProperty : Flipping property: secondservice.ribbon.ActiveConnectionsLimit to use NEXT property: niws.loadbalancer.availabilityFilteringRule.activeConnectionsLimit = 2147483647
2018-10-08 11:15:00.095 INFO [templateservice,,,] 16801 --- [onPool-worker-2] c.n.u.concurrent.ShutdownEnabledTimer : Shutdown hook installed for: NFLoadBalancer-PingTimer-secondservice
2018-10-08 11:15:00.146 INFO [templateservice,,,] 16801 --- [onPool-worker-2] c.netflix.loadbalancer.BaseLoadBalancer : Client: secondservice instantiated a LoadBalancer: DynamicServerListLoadBalancer:{NFLoadBalancer:name=secondservice,current list of Servers=[],Load balancer stats=Zone stats: {},Server stats: []}ServerList:null
2018-10-08 11:15:00.189 INFO [templateservice,,,] 16801 --- [onPool-worker-2] c.n.l.DynamicServerListLoadBalancer : Using serverListUpdater PollingServerListUpdater
2018-10-08 11:15:00.287 INFO [templateservice,,,] 16801 --- [onPool-worker-2] c.netflix.config.ChainedDynamicProperty : Flipping property: secondservice.ribbon.ActiveConnectionsLimit to use NEXT property: niws.loadbalancer.availabilityFilteringRule.activeConnectionsLimit = 2147483647
2018-10-08 11:15:00.291 INFO [templateservice,,,] 16801 --- [onPool-worker-2] c.n.l.DynamicServerListLoadBalancer : DynamicServerListLoadBalancer for client secondservice initialized: DynamicServerListLoadBalancer:{NFLoadBalancer:name=secondservice,current list of Servers=[192.168.0.205:8090, 192.168.0.205:8090],Load balancer stats=Zone stats: {defaultzone=[Zone:defaultzone; Instance count:2; Active connections count: 0; Circuit breaker tripped count: 0; Active connections per server: 0.0;]
},Server stats: [[Server:192.168.0.205:8090; Zone:defaultZone; Total Requests:0; Successive connection failure:0; Total blackout seconds:0; Last connection made:Thu Jan 01 05:30:00 IST 1970; First connection made: Thu Jan 01 05:30:00 IST 1970; Active Connections:0; total failure count in last (1000) msecs:0; average resp time:0.0; 90 percentile resp time:0.0; 95 percentile resp time:0.0; min resp time:0.0; max resp time:0.0; stddev resp time:0.0]
]}ServerList:org.springframework.cloud.netflix.ribbon.eureka.DomainExtractingServerList@3625959e
http://192.168.0.205:8090
2018-10-08 11:15:01.215 INFO [templateservice,,,] 16801 --- [erListUpdater-0] c.netflix.config.ChainedDynamicProperty : Flipping property: secondservice.ribbon.ActiveConnectionsLimit to use NEXT property: niws.loadbalancer.availabilityFilteringRule.activeConnectionsLimit = 2147483647
2018-10-08 11:15:07.951 DEBUG [templateservice,,,] 16801 --- [onPool-worker-2] c.e.m.t.clients.MessageServiceClient : [MessageServiceClient#getMessage] ---> GET http://secondservice/dummy HTTP/1.1
2018-10-08 11:15:12.527 DEBUG [templateservice,,,] 16801 --- [onPool-worker-2] c.e.m.t.clients.MessageServiceClient : [MessageServiceClient#getMessage] <--- HTTP/1.1 404 (4575ms)
2018-10-08 11:15:12.559 ERROR [templateservice,7004692c56b2e643,7004692c56b2e643,false] 16801 --- [nio-8080-exec-4] o.s.c.s.i.web.ExceptionLoggingFilter : Uncaught exception thrown
问题是,这会引发 404,当然原因是它试图点击的 url 是http://secondservice/dummy
,并且没有这样的事情。可能有助于注意,如果我设置url
FeignClient,它可以工作,但是 Eureka 的意义何在?另外,当它起作用时,fiegn 客户端会自动使用上下文路径吗?或者我必须在客户端的每个 url 中指定它?
解决方案
找到了!它与发现或配置无关,这是因为 feign 不支持上下文路径!
为了“笨拙”下来,我继续将每个配置都删除到最低限度以保持服务正常运行。当我删除第二个服务的上下文路径时,它突然起作用了。如果由其他服务设置,Feign+Ribbon 不支持自定义上下文路径。这是一个老bug,还没有修复。
有两种可能的解决方案:
- 删除上下文路径。
- 在您的 Feign 客户端中添加上下文路径。所以基本上你的 Feign 客户变成了:
// 这需要在这里才能使下面的格式正确
@FeignClient(name = "secondservice/secondservice", configuration = FeignConfig.class)
public interface MessageServiceClient {
@RequestMapping(method = RequestMethod.GET, value = "/dummy")
public String getMessage();
}
我个人不喜欢这两种解决方案。我喜欢有上下文路径,好吧,给 url 提供上下文,它通过上下文变得不言自明。但它是其他服务(secondservice)的属性,应该由该服务选择/更改。因此不应该在依赖服务中硬编码。我本来希望它得到支持,但与此同时,我将寻求:
@FeignClient(name = "${dependencies.secondservice.url}")
public interface MessageServiceClient {....}
并在 application.properties:dependencies.secondservice.url=secondservice/secondservice
中。这清楚地表明该属性由依赖项拥有,而不是由该服务拥有。
更多注意事项: 1. 我可以将请求跟踪到SynchronousMethodHandler#executeAndDecode
, response = client.execute(request, options);
。到这里,url 已解决。2. 被记录的 url:GET http://secondservice/secondservice/dummy
实际上是正确的 URL,secondservice
log 语句后的第一个字符串被替换为 IP。以下是支持该文档的文档:https ://cloud.spring.io/spring-cloud-static/Finchley.SR1/single/spring-cloud.html#_using_ribbon 。注意传递给restTemplate 的url。这就是触发寻找替代原因的原因。
推荐阅读
- javascript - 为什么我的 JS 代码不起作用?我正在尝试获取此代码以生成随机密码
- node.js - express.js - 基本应用程序路由器不工作
- android - 在 Android Studio (2.3.3) 中包含 Android 支持
- iphone - 如何在 swiftui 中使用选取器更改文本大小
- azure - 如何防止删除消息或防止对我的 azure AD App (Microsoft Graph) api 的 DELETE 请求?
- python - 在查找两个列表的公共部分的列表理解中使用 pop 有什么用?
- wordpress - 网站图像数据使用和加载时间
- flutter - 如何在 Flutter 中进行以下按钮设计
- amazon-web-services - 将 Amazon CloudFront 与 Amazon S3 Transfer Acceleration 一起使用?
- python - Django - 如何简化具有许多外键的表的创建新行?