Enhance ContentResponseHandler to be fault-tolerant
This commit enhances the `ContentResponseHandler` class to be more fault-tolerant by handling responses with null or empty bodies without throwing exceptions. If the response was successful (a 2xx status code), the `Content` object is returned. If no response body exists, `Content.NO_CONTENT` is returned. The implementation extends `ContentResponseHandler` and overrides its methods to handle the response entity and transform it into the actual response object. This is designed to be efficient and use minimal memory.
This commit is contained in:
parent
efe57e03c6
commit
0df9e63932
|
@ -28,7 +28,9 @@ package org.apache.hc.client5.http.fluent;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import org.apache.hc.client5.http.HttpResponseException;
|
||||||
import org.apache.hc.client5.http.impl.classic.AbstractHttpClientResponseHandler;
|
import org.apache.hc.client5.http.impl.classic.AbstractHttpClientResponseHandler;
|
||||||
|
import org.apache.hc.core5.http.ClassicHttpResponse;
|
||||||
import org.apache.hc.core5.http.ContentType;
|
import org.apache.hc.core5.http.ContentType;
|
||||||
import org.apache.hc.core5.http.HttpEntity;
|
import org.apache.hc.core5.http.HttpEntity;
|
||||||
import org.apache.hc.core5.http.io.entity.EntityUtils;
|
import org.apache.hc.core5.http.io.entity.EntityUtils;
|
||||||
|
@ -39,11 +41,16 @@ import org.apache.hc.core5.http.io.entity.EntityUtils;
|
||||||
* to {@link Content} instances.
|
* to {@link Content} instances.
|
||||||
*
|
*
|
||||||
* @see Content
|
* @see Content
|
||||||
*
|
|
||||||
* @since 4.4
|
* @since 4.4
|
||||||
*/
|
*/
|
||||||
public class ContentResponseHandler extends AbstractHttpClientResponseHandler<Content> {
|
public class ContentResponseHandler extends AbstractHttpClientResponseHandler<Content> {
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The maximum length of the exception message, to avoid excessive memory usage.
|
||||||
|
*/
|
||||||
|
private static final int MAX_MESSAGE_LENGTH = 256;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Content handleEntity(final HttpEntity entity) throws IOException {
|
public Content handleEntity(final HttpEntity entity) throws IOException {
|
||||||
return entity != null ?
|
return entity != null ?
|
||||||
|
@ -51,4 +58,26 @@ public class ContentResponseHandler extends AbstractHttpClientResponseHandler<Co
|
||||||
Content.NO_CONTENT;
|
Content.NO_CONTENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles a successful response (2xx status code) and returns the response entity as a {@link Content} object.
|
||||||
|
* If no response entity exists, {@link Content#NO_CONTENT} is returned.
|
||||||
|
*
|
||||||
|
* @param response the HTTP response.
|
||||||
|
* @return a {@link Content} object that encapsulates the response body, or {@link Content#NO_CONTENT} if the
|
||||||
|
* response body is {@code null} or has zero length.
|
||||||
|
* @throws HttpResponseException if the response was unsuccessful (a >= 300 status code).
|
||||||
|
* @throws IOException if an I/O error occurs.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Content handleResponse(final ClassicHttpResponse response) throws IOException {
|
||||||
|
final int statusCode = response.getCode();
|
||||||
|
final HttpEntity entity = response.getEntity();
|
||||||
|
final byte[] contentBytes = (entity != null) ? EntityUtils.toByteArray(entity, MAX_MESSAGE_LENGTH) : new byte[0];
|
||||||
|
final ContentType contentType = (entity != null && entity.getContentType() != null) ? ContentType.parse(entity.getContentType()) : ContentType.DEFAULT_BINARY;
|
||||||
|
final Content content = new Content(contentBytes, contentType);
|
||||||
|
if (statusCode >= 300) {
|
||||||
|
throw new HttpResponseException(statusCode, response.getReasonPhrase(), contentBytes, contentType);
|
||||||
|
}
|
||||||
|
return content;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
*/
|
*/
|
||||||
package org.apache.hc.client5.http;
|
package org.apache.hc.client5.http;
|
||||||
|
|
||||||
|
import org.apache.hc.core5.http.ContentType;
|
||||||
import org.apache.hc.core5.util.TextUtils;
|
import org.apache.hc.core5.util.TextUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -39,14 +40,45 @@ public class HttpResponseException extends ClientProtocolException {
|
||||||
|
|
||||||
private final int statusCode;
|
private final int statusCode;
|
||||||
private final String reasonPhrase;
|
private final String reasonPhrase;
|
||||||
|
private final byte[] contentBytes;
|
||||||
|
private final ContentType contentType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a new instance of {@code HttpResponseException} with the given
|
||||||
|
* status code and reason phrase, and no content bytes or content type.
|
||||||
|
*
|
||||||
|
* @param statusCode the HTTP status code
|
||||||
|
* @param reasonPhrase the reason phrase associated with the HTTP status code
|
||||||
|
*/
|
||||||
public HttpResponseException(final int statusCode, final String reasonPhrase) {
|
public HttpResponseException(final int statusCode, final String reasonPhrase) {
|
||||||
|
this(statusCode, reasonPhrase, null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a new instance of {@code HttpResponseException} with the given
|
||||||
|
* status code, reason phrase, content bytes, and content type.
|
||||||
|
*
|
||||||
|
* @param statusCode the HTTP status code
|
||||||
|
* @param reasonPhrase the reason phrase associated with the HTTP status code
|
||||||
|
* @param contentBytes the content bytes of the HTTP response
|
||||||
|
* @param contentType the content type of the HTTP response
|
||||||
|
*/
|
||||||
|
public HttpResponseException(final int statusCode, final String reasonPhrase, final byte[] contentBytes, final ContentType contentType) {
|
||||||
super(String.format("status code: %d" +
|
super(String.format("status code: %d" +
|
||||||
(TextUtils.isBlank(reasonPhrase) ? "" : ", reason phrase: %s"), statusCode, reasonPhrase));
|
(TextUtils.isBlank(reasonPhrase) ? "" : ", reason phrase: %s") +
|
||||||
|
(contentBytes == null ? "" : ", content: %s"),
|
||||||
|
statusCode, reasonPhrase,
|
||||||
|
contentBytes == null || contentType == null || contentType.getCharset() == null ?
|
||||||
|
null :
|
||||||
|
new String(contentBytes, contentType.getCharset())));
|
||||||
|
|
||||||
this.statusCode = statusCode;
|
this.statusCode = statusCode;
|
||||||
this.reasonPhrase = reasonPhrase;
|
this.reasonPhrase = reasonPhrase;
|
||||||
|
this.contentBytes = contentBytes;
|
||||||
|
this.contentType = contentType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public int getStatusCode() {
|
public int getStatusCode() {
|
||||||
return this.statusCode;
|
return this.statusCode;
|
||||||
}
|
}
|
||||||
|
@ -55,4 +87,11 @@ public class HttpResponseException extends ClientProtocolException {
|
||||||
return this.reasonPhrase;
|
return this.reasonPhrase;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public byte[] getContentBytes() {
|
||||||
|
return contentBytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ContentType getContentType() {
|
||||||
|
return contentType;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue