diff --git a/client/src/main/java/io/avaje/http/client/DHttpClientRequestWithRetry.java b/client/src/main/java/io/avaje/http/client/DHttpClientRequestWithRetry.java index 6d5d266..eb7cdbf 100644 --- a/client/src/main/java/io/avaje/http/client/DHttpClientRequestWithRetry.java +++ b/client/src/main/java/io/avaje/http/client/DHttpClientRequestWithRetry.java @@ -22,14 +22,34 @@ final class DHttpClientRequestWithRetry extends DHttpClientRequest { @Override protected HttpResponse performSend(HttpResponse.BodyHandler responseHandler) { HttpResponse res; - res = super.performSend(responseHandler); - if (res.statusCode() < 300) { - return res; - } - while (retryHandler.isRetry(retryCount++, res)) { - res = super.performSend(responseHandler); + HttpException ex; + + do { + try { + res = super.performSend(responseHandler); + ex = null; + } catch (final HttpException e) { + ex = e; + res = null; + } + if (res != null && res.statusCode() < 300) { + return res; + } + retryCount++; + } while (retry(res, ex)); + + if (res == null && ex != null) { + throw ex; } + return res; } + protected boolean retry(HttpResponse res, HttpException ex) { + + if (res != null) { + return retryHandler.isRetry(retryCount, res); + } + return retryHandler.isExceptionRetry(retryCount, ex); + } } diff --git a/client/src/main/java/io/avaje/http/client/HttpException.java b/client/src/main/java/io/avaje/http/client/HttpException.java index fe0fbdb..0c83020 100644 --- a/client/src/main/java/io/avaje/http/client/HttpException.java +++ b/client/src/main/java/io/avaje/http/client/HttpException.java @@ -91,28 +91,37 @@ public HttpException(int statusCode, Throwable cause) { } /** - * Return the response body content as a bean + * Return the response body content as a bean, or else null if body content doesn't exist. * * @param cls The type of bean to convert the response to * @return The response as a bean */ public T bean(Class cls) { + if (httpResponse == null) { + return null; + } final BodyContent body = context.readErrorContent(responseAsBytes, httpResponse); return context.readBean(cls, body); } /** - * Return the response body content as a UTF8 string. + * Return the response body content as a UTF8 string, or else null if body content doesn't exist. */ public String bodyAsString() { + if (httpResponse == null) { + return null; + } final BodyContent body = context.readErrorContent(responseAsBytes, httpResponse); return new String(body.content(), StandardCharsets.UTF_8); } - /** - * Return the response body content as raw bytes. + /** + * Return the response body content as raw bytes, or else null if body content doesn't exist. */ public byte[] bodyAsBytes() { + if (httpResponse == null) { + return null; + } final BodyContent body = context.readErrorContent(responseAsBytes, httpResponse); return body.content(); } diff --git a/client/src/main/java/io/avaje/http/client/RetryHandler.java b/client/src/main/java/io/avaje/http/client/RetryHandler.java index 67ed83d..e9d16ba 100644 --- a/client/src/main/java/io/avaje/http/client/RetryHandler.java +++ b/client/src/main/java/io/avaje/http/client/RetryHandler.java @@ -11,9 +11,19 @@ public interface RetryHandler { * Return true if the request should be retried. * * @param retryCount The number of retry attempts already executed - * @param response The HTTP response + * @param response The HTTP response * @return True if the request should be retried or false if not */ boolean isRetry(int retryCount, HttpResponse response); + /** + * Return true if the request should be retried. + * + * @param retryCount The number of retry attempts already executed + * @param exception The Wrapped Error thrown by the underlying Http Client + * @return True if the request should be retried or false if not + */ + default boolean isExceptionRetry(int retryCount, HttpException exception) { + throw exception; + } }