2025.6.1
这些错误表明你的异步 HTTP 请求在调用外部 API 时失败了,主要涉及两个关键问题:
1. UnresolvedAddressException(根本原因)
-
错误表现:
Caused by: java.nio.channels.UnresolvedAddressException -
原因:
- 在构造
HttpRequest时,提供的 API URL 可能包含无法解析的主机名(比如拼写错误、未配置 DNS 或网络不可达)。 - 例如:
https://example.com/api中的example.com无法解析为有效 IP 地址。
- 在构造
-
解决方案:
- 检查 URL 是否正确:
String apiUrl = "https://example.com/api?param=" + URLEncoder.encode(url, StandardCharsets.UTF_8); System.out.println("尝试请求的URL: " + apiUrl); // 确认URL有效 - 验证网络连通性:
- 在服务器上执行
ping example.com或nslookup example.com,确认域名可解析。
- 在服务器上执行
- 使用完整的有效 URL:
- 如果 API 在本地开发环境,确保使用正确的 IP 或
localhost(如http://localhost:8080/api)。
- 如果 API 在本地开发环境,确保使用正确的 IP 或
- 检查 URL 是否正确:
2. ConnectException(直接原因)
-
错误表现:
java.net.ConnectException -
原因:
- 由于
UnresolvedAddressException导致连接无法建立。 - 也可能是目标服务未启动、防火墙拦截或端口错误。
- 由于
-
解决方案:
- 添加超时和重试机制:
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) { 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)因此失败,需要手动管理事务。
- MyBatis 在异步线程中自动关闭了未绑定事务的
-
解决方案:
- 在异步任务中显式控制事务:
@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; // 或记录失败状态到数据库
}
}
总结建议
- 优先解决
UnresolvedAddressException- 确认 API URL 可访问(直接在浏览器或
curl中测试)。
- 确认 API URL 可访问(直接在浏览器或
- 增强健壮性
- 添加超时、重试、事务管理。
- 监控异步任务
- 记录任务状态到数据库,便于排查问题。
- 日志标准化
- 使用
log.error()替代e.printStackTrace(),便于集中收集日志。
- 使用

浙公网安备 33010602011771号