2025.6.1

这些错误表明你的异步 HTTP 请求在调用外部 API 时失败了,主要涉及两个关键问题:


1. UnresolvedAddressException(根本原因)

  • 错误表现

    Caused by: java.nio.channels.UnresolvedAddressException
    
  • 原因

    • 在构造 HttpRequest 时,提供的 API URL 可能包含无法解析的主机名(比如拼写错误、未配置 DNS 或网络不可达)。
    • 例如:https://example.com/api 中的 example.com 无法解析为有效 IP 地址。
  • 解决方案

    1. 检查 URL 是否正确
      String apiUrl = "https://example.com/api?param=" + URLEncoder.encode(url, StandardCharsets.UTF_8);
      System.out.println("尝试请求的URL: " + apiUrl); // 确认URL有效
      
    2. 验证网络连通性
      • 在服务器上执行 ping example.comnslookup example.com,确认域名可解析。
    3. 使用完整的有效 URL
      • 如果 API 在本地开发环境,确保使用正确的 IP 或 localhost(如 http://localhost:8080/api)。

2. ConnectException(直接原因)

  • 错误表现

    java.net.ConnectException
    
  • 原因

    • 由于 UnresolvedAddressException 导致连接无法建立。
    • 也可能是目标服务未启动、防火墙拦截或端口错误。
  • 解决方案

    1. 添加超时和重试机制
      HttpRequest request = HttpRequest.newBuilder()
              .uri(URI.create(apiUrl))
              .timeout(Duration.ofSeconds(10)) // 必须设置超时
              .GET()
              .build();
      
    2. 捕获并处理连接异常
      try {
          HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
          if (response.statusCode() != 200) {
              log.error("API 返回错误状态码: {}", response.statusCode());
          }
      } catch (ConnectException e) {
          log.error("无法连接到API服务: {}", apiUrl, e);
          // 可选:重试逻辑或记录失败状态到数据库
      }
      

3. Closing non-transactional SqlSession(连带问题)

  • 错误表现

    Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@61f28556]
    
  • 原因

    • MyBatis 在异步线程中自动关闭了未绑定事务的 SqlSession,但这不是错误,只是日志提示。
    • 如果后续操作(如 resumeMapper.update)因此失败,需要手动管理事务。
  • 解决方案

    • 在异步任务中显式控制事务:
      @Transactional(propagation = Propagation.REQUIRES_NEW) // 新事务
      public void DocParser(String url, Resume resume) throws Exception {
          // 解析逻辑...
          resumeMapper.update(resume, updateWrapper);
      }
      
    • 或通过 TransactionTemplate 编程式事务:
      @Autowired
      private TransactionTemplate transactionTemplate;
      
      CompletableFuture.runAsync(() -> {
          transactionTemplate.execute(status -> {
              try {
                  DocParser(finalUrl, resume);
              } catch (Exception e) {
                  status.setRollbackOnly();
                  log.error("事务回滚", e);
              }
              return null;
          });
      }, asyncExecutor);
      

完整改进代码

public void DocParser(String url, Resume resume) throws Exception {
    String apiUrl = "https://example.com/api?param=" + URLEncoder.encode(url, StandardCharsets.UTF_8);
    log.info("调用API: {}", apiUrl);

    HttpClient client = HttpClient.newBuilder()
            .connectTimeout(Duration.ofSeconds(10))
            .build();

    HttpRequest request = HttpRequest.newBuilder()
            .uri(URI.create(apiUrl))
            .timeout(Duration.ofSeconds(10))
            .GET()
            .build();

    try {
        HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
        if (response.statusCode() == 200) {
            String result = response.body();
            LambdaUpdateWrapper<Resume> updateWrapper = new LambdaUpdateWrapper<>();
            updateWrapper.eq(Resume::getId, resume.getId())
                    .set(Resume::getFileContent, result);
            resumeMapper.update(resume, updateWrapper);
        } else {
            log.error("API 返回异常状态码: {}", response.statusCode());
        }
    } catch (ConnectException e) {
        log.error("API 连接失败,请检查网络或服务是否可用: {}", apiUrl, e);
        throw e; // 或记录失败状态到数据库
    }
}

总结建议

  1. 优先解决 UnresolvedAddressException
    • 确认 API URL 可访问(直接在浏览器或 curl 中测试)。
  2. 增强健壮性
    • 添加超时、重试、事务管理。
  3. 监控异步任务
    • 记录任务状态到数据库,便于排查问题。
  4. 日志标准化
    • 使用 log.error() 替代 e.printStackTrace(),便于集中收集日志。
posted @ 2025-06-01 23:32  258333  阅读(120)  评论(0)    收藏  举报