Spring 启动: Connection timed out when trying to call a service from a service

标签 spring spring-boot spring-mvc spring-security netflix-eureka

我有 2 个微服务 + 一个注册它们的 Eureka 服务器。 我真的做了我能想到的一切,但是当我尝试从管理服务调用登录服务时,我总是得到“连接超时”。

POST http://localhost:9903/login

{
    "username":"adm4",
    "password":"adm4adm4"
}

我尝试使用 Spring RestTemplate 和 WebClient 以及 Apache HttpClient。 每次,流程都到达 post 方法,我得到相同的结果。 我想这一定是一些配置问题。

我正在使用所有模块在本地主机上工作。

这真的让我抓狂!

请指教。我很感激。

相关信息如下。如果您需要更多信息,请告诉我。

首先您可以看到服务已注册并启动:

enter image description here

接下来的代码:

经理(调用)服务: (我把之前所有的尝试都留在里面评论了)

@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 包含正文内容。

最佳答案

这不是一个完整的答案,但我希望它能帮助您解决问题。

我认为您的问题可能与您计算机的不同 IP 地址混合有关。

首先,我认为 Eureka 正在暴露您的服务,如 host.docker.internal ,如所示,通过不同的 docker 容器引用主机的逻辑名称,原因在 this SO question 中解释。

基本上,docker 软件似乎正在使用 host.docker.internalgateway.docker.internal 条目更新您的 hosts 文件> 并且 Eureka 可能会将该别名作为正在通告的机器 IP 的别名。请参阅上述问题中已接受的答案。

当您正常运行 Spring Boot 时,底层服务器(Tomcat、Jetty、Undertow)将监听 0.0.0.0 地址中的连接,即所有可用的网络接口(interface),包括 本地主机。这让我很困扰,因为正如所指出的,该服务应该可以通过机器中的所有 IP 访问。

无论如何,我认为您可以尝试多种方法来解决您的问题。

解决该问题的最佳方法可能是将 Eureka 服务器和/或 Eureka 客户端的主机名配置为通用主机名。

例如,您可以将服务器和客户端配置为公开为 localhost

为此,您需要在各自的配置文件中包含以下配置属性:

eureka:
  instance:
    hostname: localhost

关于 Spring 启动: Connection timed out when trying to call a service from a service,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65484347/

相关文章:

java - 在 Spring MVC 中使用 ApplicationContext.xml 创建的对象的生命周期

spring - 防止 Spring Boot 注册 servlet 过滤器

spring-mvc - 在 SpringBootTest 中测试 COR

json - Selenium 远程 Web 驱动程序给出 java.lang.NoSuchMethodError : com. google.common.collect.Multimaps.transformValues

java - 使用 BeanUtils 或类似工具将非空属性从一个对象复制到另一个对象

Spring 的 ReloadableResourceBundleMessageSource 没有找到属性文件

java - Spring 是否自动在 Java bean 定义中 Autowiring 构造函数参数?

spring-boot - 无法在 zipkin UI 依赖项选项卡中查看任何 'dependencies'

java - 在远程调试中暂停 Spring Boot Java 应用程序时,ECS 代理停止并重新启动 Docker 容器

java - 在我的情况下,BindingResult 或 FieldErrors 或 GlobalErrors 可以为 null 吗?