Skip to content

Commit 3c44a1c

Browse files
authored
DATAES-863 - Improve server error response handling.
Original PR: spring-projects#480
1 parent 384e52b commit 3c44a1c

File tree

1 file changed

+60
-31
lines changed

1 file changed

+60
-31
lines changed

src/main/java/org/springframework/data/elasticsearch/client/reactive/DefaultReactiveElasticsearchClient.java

Lines changed: 60 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -804,53 +804,82 @@ private static XContentParser createParser(String mediaType, String content) thr
804804

805805
private <T> Publisher<? extends T> handleServerError(Request request, ClientResponse response) {
806806

807-
RestStatus status = RestStatus.fromCode(response.statusCode().value());
807+
int statusCode = response.statusCode().value();
808+
RestStatus status = RestStatus.fromCode(statusCode);
809+
String mediaType = response.headers().contentType().map(MediaType::toString).orElse(XContentType.JSON.mediaType());
808810

809-
return Mono.error(new ElasticsearchStatusException(String.format("%s request to %s returned error code %s.",
810-
request.getMethod(), request.getEndpoint(), response.statusCode().value()), status));
811+
return response.body(BodyExtractors.toMono(byte[].class)) //
812+
.map(bytes -> new String(bytes, StandardCharsets.UTF_8)) //
813+
.flatMap(content -> contentOrError(content, mediaType, status))
814+
.flatMap(unused -> Mono
815+
.error(new ElasticsearchStatusException(String.format("%s request to %s returned error code %s.",
816+
request.getMethod(), request.getEndpoint(), statusCode), status)));
811817
}
812818

813819
private <T> Publisher<? extends T> handleClientError(String logId, Request request, ClientResponse response,
814820
Class<T> responseType) {
815821

822+
int statusCode = response.statusCode().value();
823+
RestStatus status = RestStatus.fromCode(statusCode);
824+
String mediaType = response.headers().contentType().map(MediaType::toString).orElse(XContentType.JSON.mediaType());
825+
816826
return response.body(BodyExtractors.toMono(byte[].class)) //
817827
.map(bytes -> new String(bytes, StandardCharsets.UTF_8)) //
818-
.flatMap(content -> {
819-
String mediaType = response.headers().contentType().map(MediaType::toString)
820-
.orElse(XContentType.JSON.mediaType());
821-
RestStatus status = RestStatus.fromCode(response.statusCode().value());
822-
try {
823-
ElasticsearchException exception = getElasticsearchException(response, content, mediaType);
824-
if (exception != null) {
825-
StringBuilder sb = new StringBuilder();
826-
buildExceptionMessages(sb, exception);
827-
return Mono.error(new ElasticsearchStatusException(sb.toString(), status, exception));
828-
}
829-
} catch (Exception e) {
830-
return Mono.error(new ElasticsearchStatusException(content, status));
831-
}
832-
return Mono.just(content);
833-
}).doOnNext(it -> ClientLogger.logResponse(logId, response.statusCode(), it)) //
828+
.flatMap(content -> contentOrError(content, mediaType, status)) //
829+
.doOnNext(content -> ClientLogger.logResponse(logId, response.statusCode(), content)) //
834830
.flatMap(content -> doDecode(response, responseType, content));
835831
}
836832

837833
// region ElasticsearchException helper
834+
/**
835+
* checks if the given content body contains an {@link ElasticsearchException}, if yes it is returned in a Mono.error.
836+
* Otherwise the content is returned in the Mono
837+
*
838+
* @param content the content to analyze
839+
* @param mediaType the returned media type
840+
* @param status the response status
841+
* @return a Mono with the content or an Mono.error
842+
*/
843+
private static Mono<String> contentOrError(String content, String mediaType, RestStatus status) {
844+
845+
ElasticsearchException exception = getElasticsearchException(content, mediaType, status);
846+
847+
if (exception != null) {
848+
StringBuilder sb = new StringBuilder();
849+
buildExceptionMessages(sb, exception);
850+
return Mono.error(new ElasticsearchStatusException(sb.toString(), status, exception));
851+
}
852+
853+
return Mono.just(content);
854+
}
855+
856+
/**
857+
* tries to parse an {@link ElasticsearchException} from the given body content
858+
*
859+
* @param content the content to analyse
860+
* @param mediaType the type of the body content
861+
* @return an {@link ElasticsearchException} or {@literal null}.
862+
*/
838863
@Nullable
839-
private ElasticsearchException getElasticsearchException(ClientResponse response, String content, String mediaType)
840-
throws IOException {
864+
private static ElasticsearchException getElasticsearchException(String content, String mediaType, RestStatus status) {
841865

842-
XContentParser parser = createParser(mediaType, content);
843-
// we have a JSON object with an error and a status field
844-
XContentParser.Token token = parser.nextToken(); // Skip START_OBJECT
866+
try {
867+
XContentParser parser = createParser(mediaType, content);
868+
// we have a JSON object with an error and a status field
869+
XContentParser.Token token = parser.nextToken(); // Skip START_OBJECT
845870

846-
do {
847-
token = parser.nextToken();
871+
do {
872+
token = parser.nextToken();
848873

849-
if (parser.currentName().equals("error")) {
850-
return ElasticsearchException.failureFromXContent(parser);
851-
}
852-
} while (token == XContentParser.Token.FIELD_NAME);
853-
return null;
874+
if (parser.currentName().equals("error")) {
875+
return ElasticsearchException.failureFromXContent(parser);
876+
}
877+
} while (token == XContentParser.Token.FIELD_NAME);
878+
879+
return null;
880+
} catch (IOException e) {
881+
return new ElasticsearchStatusException(content, status);
882+
}
854883
}
855884

856885
private static void buildExceptionMessages(StringBuilder sb, Throwable t) {

0 commit comments

Comments
 (0)