使用Apache CloseableHttpAsyncClient识别不可访问URL避免404触发超时重试
解决方案
根因说明
你遇到的问题本质是部分异常服务端返回404状态码后,既不主动关闭连接,也不发送完整的响应内容,导致客户端一直挂起等待读取,直到触发10秒SocketTimeout,而你当前的重试逻辑又会对超时异常触发重试,最终导致无效请求额外产生20秒延迟。
具体优化方案
1. 新增响应状态码前置校验逻辑
拿到HttpResponse实例后第一时间校验状态码,4xx/5xx类错误直接抛出对应业务异常,不要继续读取响应内容,避免无意义等待:
Future<HttpResponse> httpResponseFuture = asyncCloseableHttpClient.execute(httpUriRequest, null); try { HttpResponse response = httpResponseFuture.get(10000, TimeUnit.MILLISECONDS); // 新增状态码校验 int status = response.getStatusLine().getStatusCode(); if (status == HttpStatus.SC_NOT_FOUND) { throw new DownloadResourceNotFoundException("Resource not found, status code: 404"); } if (status >= 400) { throw new DownloadFailedException("Request failed with status code: " + status); } return response; } catch (ExecutionException e) { // 原有异常处理逻辑保持不变 Throwable cause = e.getCause() != null ? e.getCause() : e; if (cause instanceof ConnectException) { throw new DownloadConnectionException("ConnectionException " + cause, DOWNLOAD_FAILED, cause); } if (cause instanceof SocketTimeoutException) { throw new DownloadTimeoutException(DOWNLOAD_TIMEOUT_EXCEPTION); } if (cause instanceof ConnectionClosedException) { throw new DownloadConnectionClosedException("ConnectionClosedException " + DOWNLOAD_FAILED, cause); } if(cause instanceof UnsupportedCharsetException) { throw new BadRequestException("Image download failed with UnsupportedCharsetException " + cause, INVALID_CONTENT_TYPE_EXCEPTION, cause); } } catch (TimeoutException e) { throw new DownloadTimeoutException(DOWNLOAD_TIMEOUT_EXCEPTION); }
注意:需要先自定义
DownloadResourceNotFoundException等业务异常,不要归类到超时异常类。
2. 调整重试规则,排除非超时类异常触发重试
修改重试配置,仅对明确的超时类异常重试,新增404等资源不存在异常的排除逻辑:
RetryConfig.custom() .maxAttempts(downloadAttempts) .retryOnException(e -> (e instanceof DownloadTimeoutException)) // 新增排除逻辑,资源不存在类异常绝不重试 .retryOnException(e -> !(e instanceof DownloadResourceNotFoundException)) .waitDuration(Duration.ofMillis(30)) .build();
3. 可选优化:添加响应超时控制
如果还是遇到部分服务端挂起连接的问题,可以额外配置setConnectionRequestTimeout,或者使用HttpAsyncResponseConsumer来控制响应的整体读取时长,避免无限等待。
// RequestConfig新增连接请求超时配置 RequestConfig config = RequestConfig.custom() .setSocketTimeout(10000) .setConnectTimeout(5000) .setConnectionRequestTimeout(3000) // 新增,从连接池获取连接的超时时间 .setRedirectsEnabled(true) .setMaxRedirects(3) .setStaleConnectionCheckEnabled(false) .setProxyPreferredAuthSchemes(Arrays.asList(AuthSchemes.BASIC)) .build();
验证效果
优化后,只要服务端返回了404状态码,会立刻触发资源不存在异常,不会进入读取等待逻辑,也不会触发重试,可将无效URL的请求耗时从20秒降低到毫秒级。
内容的提问来源于stack exchange,提问作者amit kumar
相关产品推荐
相关产品推荐

