Issue
I have 2 microservices + an Eureka Server in which they are registerd. I made really everything I could think of, yet when I try to call the login service from the manager service, I always get "Connection timed out".
POST http://localhost:9903/login
{
"username":"adm4",
"password":"adm4adm4"
}
I have tried to work with Spring RestTemplate and WebClient and also Apache HttpClient. All the times, the flow reaches the post method, and I get the same result. I guess it must be some configuration issue.
I am working on localhost with all modules.
It really drives me crzay!
Please advise. I appreciate it.
The relevant info is as follows. Please tell me if you need more info.
First of all you can see that the services are registered and up:
Next the code:
Manager (calling) Service: (I left inside all my previous attempts commented)
@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
If I understand well, the request does not reach the login service at all.
Login (called) service:
@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 file:
server.port: 9902
spring:
application:
name: bbsim-login-service
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8088/eureka/
registryFetchIntervalSeconds: 1
instance:
leaseRenewalIntervalInSeconds: 1
I addition, I tried the following - giving me the same results:
curl -d "@data.json" -H "Content-Type: application/json" -X POST http://localhost:9903/login
where data.json has the body contents.
Solution
This will not be a complete answer but I hope it helps you with your issue.
I think your problem could be related with a mix of the different IP address of your machine.
First, I think Eureka is exposing your services like host.docker.internal
, as indicated, the logical name that references the host machine through the different docker containers, for the reason explained in this SO question.
Basically, it seems that the docker software is updating your hosts
file with entries for host.docker.internal
and gateway.docker.internal
and Eureka probably is taking that alias as the one for the machine IP that is being advertised. Please, see the accepted answer in the aforementioned question.
When you run Spring Boot normally the underlying server (Tomcat, Jetty, Undertow) will listen for connections in the 0.0.0.0
address, i.e., in all the network interfaces available, including localhost
. This is what troubles me, because as indicated, the service should be accessible through all the IPs in the machine.
In any way, I think you can try several things to solve your issue.
Probably the best approach to solve the problem will be to configure the hostname
of your Eureka server and/or your Eureka clients to a common one.
For example, you can configure your server and clients to be exposed as localhost
.
For that purpose, you need to include the following configuration property in their respective config files:
eureka:
instance:
hostname: localhost
Answered By - jccampanero