Spring 引导:尝试从服务调用服务时连接超时
Spring Boot: Connection timed out when trying to call a service from a service
我有 2 个微服务 + 一个在其中注册的 Eureka 服务器。
我真的做了我能想到的一切,但是当我尝试从管理器服务调用登录服务时,我总是得到“连接超时”。
POST http://localhost:9903/login
{
"username":"adm4",
"password":"adm4adm4"
}
我尝试使用 Spring RestTemplate 和 WebClient 以及 Apache HttpClient。
一直以来,流程都到达 post 方法,我得到了相同的结果。
我想这一定是一些配置问题。
我正在使用所有模块在本地主机上工作。
这真让我发疯!
请指教。我很感激。
相关信息如下。如果您需要更多信息,请告诉我。
首先您可以看到服务已注册并启动:
下一个代码:
经理(呼叫)服务:
(我在里面留下了我之前所有的尝试评论)
@PostMapping("/login")
public void login(@RequestBody LoginRequest loginRequest) throws Exception {
String url = getBaseUrl("bbsim-login-service") + "/api/auth/signin";
/* CloseableHttpClient httpclient = HttpClients.createDefault();
try {
HttpPost httpPost = new HttpPost(getBaseUrl("bbsim-login-service") + "/api/auth/signin");
List<NameValuePair> params = new ArrayList<>();
params.add(new BasicNameValuePair("username", loginRequest.getUsername()));
params.add(new BasicNameValuePair("password", loginRequest.getPassword()));
httpPost.setEntity(new UrlEncodedFormEntity(params));
CloseableHttpResponse response = httpclient.execute(httpPost);
System.out.println(response.getStatusLine().getStatusCode());
} finally {
httpclient.close();
}
*/
/* HttpComponentsClientHttpRequestFactory clientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory();
// Connect timeout: time is in milliseconds
clientHttpRequestFactory.setConnectTimeout(30000);
// Read timeout: time is in milliseconds
clientHttpRequestFactory.setReadTimeout(30000);
RestTemplate restTemplate = new RestTemplate(clientHttpRequestFactory);
HttpEntity<LoginRequest> request = new HttpEntity<>(loginRequest);
JwtResponse res = restTemplate.postForObject(url, request, JwtResponse.class);
System.out.println(res);
*/
localApiClient
.post()
.uri(url)
.body(Mono.just(loginRequest), LoginRequest.class)
.retrieve()
.bodyToMono(JwtResponse.class)
.block();
}
private String getBaseUrl(String serviceName) {
Application application = eurekaClient.getApplication(serviceName);
InstanceInfo instanceInfo = application.getInstances().get(0);
String hostname = instanceInfo.getHostName();
int port = instanceInfo.getPort();
return "http://" + hostname + ":" + port;
}
application.yml:
server.port: 9903
spring:
application.name: bbsim-manager-service
eureka:
client:
serviceUrl:
defaultZone: ${EUREKA_URI:http://localhost:8088/eureka}
registryFetchIntervalSeconds: 1
# register-with-eureka: true
# fetch-registry: true
instance:
leaseRenewalIntervalInSeconds: 1
如果我理解的很好,请求根本没有到达登录服务。
登录(调用)服务:
@PostMapping("/signin")
public ResponseEntity<?> authenticateUser(@Valid @RequestBody LoginRequest loginRequest) {
Authentication authentication = authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(loginRequest.getUsername(), loginRequest.getPassword()));
SecurityContextHolder.getContext().setAuthentication(authentication);
String jwt = jwtUtils.generateJwtToken(authentication);
UserDetailsImpl userDetails = (UserDetailsImpl) authentication.getPrincipal();
List<String> roles = userDetails.getAuthorities().stream()
.map(item -> item.getAuthority())
.collect(Collectors.toList());
return ResponseEntity.ok().body(new JwtResponse(jwt,
userDetails.getId(),
userDetails.getUsername(),
userDetails.getEmail(),
roles));
}
application.yml 文件:
server.port: 9902
spring:
application:
name: bbsim-login-service
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8088/eureka/
registryFetchIntervalSeconds: 1
instance:
leaseRenewalIntervalInSeconds: 1
此外,我尝试了以下 - 给出了相同的结果:
curl -d "@data.json" -H "Content-Type: application/json" -X POST http://localhost:9903/login
其中 data.json 包含正文内容。
看起来您正在使用 Docker。您正在尝试连接到 localhost,但其他容器中的其他服务 运行 因此 localhost 将无法工作。请在 YAML 文件中尝试 0.0.0.0
或 host.docker.internal
看看是否可行。
换句话说,您需要编辑以下内容。
server.port: 9903
spring:
application.name: bbsim-manager-service
eureka:
client:
serviceUrl:
defaultZone: ${EUREKA_URI:http://host.docker.internal:8088/eureka}
registryFetchIntervalSeconds: 1
# register-with-eureka: true
# fetch-registry: true
instance:
leaseRenewalIntervalInSeconds: 1
或更改 EUREKA_URI
环境变量以反映这一点。同样在您的服务中 YAML
server.port: 9902
spring:
application:
name: bbsim-login-service
eureka:
client:
serviceUrl:
defaultZone: ${EUREKA_URI:http://host.docker.internal:8088/eureka/}
registryFetchIntervalSeconds: 1
instance:
leaseRenewalIntervalInSeconds: 1
这不是一个完整的答案,但我希望它能帮助您解决问题。
我认为您的问题可能与您机器的不同 IP 地址混合使用有关。
首先,我认为 Eureka 公开了您的服务,如 host.docker.internal
,如前所述,通过不同的 docker 容器引用主机的逻辑名称,原因在 [=19] 中解释=].
基本上,docker 软件似乎正在使用 host.docker.internal
和 gateway.docker.internal
的条目更新您的 hosts
文件,而 Eureka 可能正在使用该别名对于正在宣传的机器 IP。请参阅上述问题中已接受的答案。
当您 运行 Spring 正常启动时,底层服务器(Tomcat、Jetty、Undertow)将侦听 0.0.0.0
地址中的连接,即在所有可用的网络接口,包括 localhost
。这就是困扰我的地方,因为如前所述,应该可以通过机器中的所有 IP 访问该服务。
无论如何,我认为您可以尝试几种方法来解决您的问题。
可能解决该问题的最佳方法是将您的 Eureka 服务器 hostname
and/or 您的 Eureka 客户端配置为通用客户端。
例如,您可以将服务器和客户端配置为公开为 localhost
。
为此,您需要在各自的配置文件中包含以下配置 属性:
eureka:
instance:
hostname: localhost
我有 2 个微服务 + 一个在其中注册的 Eureka 服务器。 我真的做了我能想到的一切,但是当我尝试从管理器服务调用登录服务时,我总是得到“连接超时”。
POST http://localhost:9903/login
{
"username":"adm4",
"password":"adm4adm4"
}
我尝试使用 Spring RestTemplate 和 WebClient 以及 Apache HttpClient。 一直以来,流程都到达 post 方法,我得到了相同的结果。 我想这一定是一些配置问题。
我正在使用所有模块在本地主机上工作。
这真让我发疯!
请指教。我很感激。
相关信息如下。如果您需要更多信息,请告诉我。
首先您可以看到服务已注册并启动:
下一个代码:
经理(呼叫)服务: (我在里面留下了我之前所有的尝试评论)
@PostMapping("/login")
public void login(@RequestBody LoginRequest loginRequest) throws Exception {
String url = getBaseUrl("bbsim-login-service") + "/api/auth/signin";
/* CloseableHttpClient httpclient = HttpClients.createDefault();
try {
HttpPost httpPost = new HttpPost(getBaseUrl("bbsim-login-service") + "/api/auth/signin");
List<NameValuePair> params = new ArrayList<>();
params.add(new BasicNameValuePair("username", loginRequest.getUsername()));
params.add(new BasicNameValuePair("password", loginRequest.getPassword()));
httpPost.setEntity(new UrlEncodedFormEntity(params));
CloseableHttpResponse response = httpclient.execute(httpPost);
System.out.println(response.getStatusLine().getStatusCode());
} finally {
httpclient.close();
}
*/
/* HttpComponentsClientHttpRequestFactory clientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory();
// Connect timeout: time is in milliseconds
clientHttpRequestFactory.setConnectTimeout(30000);
// Read timeout: time is in milliseconds
clientHttpRequestFactory.setReadTimeout(30000);
RestTemplate restTemplate = new RestTemplate(clientHttpRequestFactory);
HttpEntity<LoginRequest> request = new HttpEntity<>(loginRequest);
JwtResponse res = restTemplate.postForObject(url, request, JwtResponse.class);
System.out.println(res);
*/
localApiClient
.post()
.uri(url)
.body(Mono.just(loginRequest), LoginRequest.class)
.retrieve()
.bodyToMono(JwtResponse.class)
.block();
}
private String getBaseUrl(String serviceName) {
Application application = eurekaClient.getApplication(serviceName);
InstanceInfo instanceInfo = application.getInstances().get(0);
String hostname = instanceInfo.getHostName();
int port = instanceInfo.getPort();
return "http://" + hostname + ":" + port;
}
application.yml:
server.port: 9903
spring:
application.name: bbsim-manager-service
eureka:
client:
serviceUrl:
defaultZone: ${EUREKA_URI:http://localhost:8088/eureka}
registryFetchIntervalSeconds: 1
# register-with-eureka: true
# fetch-registry: true
instance:
leaseRenewalIntervalInSeconds: 1
如果我理解的很好,请求根本没有到达登录服务。
登录(调用)服务:
@PostMapping("/signin")
public ResponseEntity<?> authenticateUser(@Valid @RequestBody LoginRequest loginRequest) {
Authentication authentication = authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(loginRequest.getUsername(), loginRequest.getPassword()));
SecurityContextHolder.getContext().setAuthentication(authentication);
String jwt = jwtUtils.generateJwtToken(authentication);
UserDetailsImpl userDetails = (UserDetailsImpl) authentication.getPrincipal();
List<String> roles = userDetails.getAuthorities().stream()
.map(item -> item.getAuthority())
.collect(Collectors.toList());
return ResponseEntity.ok().body(new JwtResponse(jwt,
userDetails.getId(),
userDetails.getUsername(),
userDetails.getEmail(),
roles));
}
application.yml 文件:
server.port: 9902
spring:
application:
name: bbsim-login-service
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8088/eureka/
registryFetchIntervalSeconds: 1
instance:
leaseRenewalIntervalInSeconds: 1
此外,我尝试了以下 - 给出了相同的结果:
curl -d "@data.json" -H "Content-Type: application/json" -X POST http://localhost:9903/login
其中 data.json 包含正文内容。
看起来您正在使用 Docker。您正在尝试连接到 localhost,但其他容器中的其他服务 运行 因此 localhost 将无法工作。请在 YAML 文件中尝试 0.0.0.0
或 host.docker.internal
看看是否可行。
换句话说,您需要编辑以下内容。
server.port: 9903
spring:
application.name: bbsim-manager-service
eureka:
client:
serviceUrl:
defaultZone: ${EUREKA_URI:http://host.docker.internal:8088/eureka}
registryFetchIntervalSeconds: 1
# register-with-eureka: true
# fetch-registry: true
instance:
leaseRenewalIntervalInSeconds: 1
或更改 EUREKA_URI
环境变量以反映这一点。同样在您的服务中 YAML
server.port: 9902
spring:
application:
name: bbsim-login-service
eureka:
client:
serviceUrl:
defaultZone: ${EUREKA_URI:http://host.docker.internal:8088/eureka/}
registryFetchIntervalSeconds: 1
instance:
leaseRenewalIntervalInSeconds: 1
这不是一个完整的答案,但我希望它能帮助您解决问题。
我认为您的问题可能与您机器的不同 IP 地址混合使用有关。
首先,我认为 Eureka 公开了您的服务,如 host.docker.internal
,如前所述,通过不同的 docker 容器引用主机的逻辑名称,原因在 [=19] 中解释=].
基本上,docker 软件似乎正在使用 host.docker.internal
和 gateway.docker.internal
的条目更新您的 hosts
文件,而 Eureka 可能正在使用该别名对于正在宣传的机器 IP。请参阅上述问题中已接受的答案。
当您 运行 Spring 正常启动时,底层服务器(Tomcat、Jetty、Undertow)将侦听 0.0.0.0
地址中的连接,即在所有可用的网络接口,包括 localhost
。这就是困扰我的地方,因为如前所述,应该可以通过机器中的所有 IP 访问该服务。
无论如何,我认为您可以尝试几种方法来解决您的问题。
可能解决该问题的最佳方法是将您的 Eureka 服务器 hostname
and/or 您的 Eureka 客户端配置为通用客户端。
例如,您可以将服务器和客户端配置为公开为 localhost
。
为此,您需要在各自的配置文件中包含以下配置 属性:
eureka:
instance:
hostname: localhost