forked from spring-projects/spring-framework
/
DefaultHttpErrorDetailsExtractor.java
138 lines (115 loc) · 4.19 KB
/
DefaultHttpErrorDetailsExtractor.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
package org.springframework.web.client;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.net.URI;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import org.jetbrains.annotations.NotNull;
import org.springframework.http.HttpMethod;
import org.springframework.lang.Nullable;
/**
* Spring's default implementation of the {@link HttpErrorDetailsExtractor} interface.
*
* <p>This extractor will compose a short summary of the http error response, including:
* <ul>
* <li>request URI
* <li>request method
* <li>a 200-character preview of the response body, unformatted
* </ul>
*
* An example:
* <pre>
* 404 Not Found after GET http://example.com:8080/my-endpoint : [{'id': 123, 'message': 'my very long... (500 bytes)]</code>
* </pre>
*
* @author Jerzy Krolak
* @since 5.1
* @see DefaultResponseErrorHandler#setHttpErrorDetailsExtractor(HttpErrorDetailsExtractor)
*/
public class DefaultHttpErrorDetailsExtractor implements HttpErrorDetailsExtractor {
private static final int MAX_BODY_BYTES_LENGTH = 400;
private static final int MAX_BODY_CHARS_LENGTH = 200;
/**
* Assemble a short summary of the HTTP error response.
* @param rawStatusCode HTTP status code
* @param statusText HTTP status text
* @param responseBody response body
* @param responseCharset response charset
* @param url request URI
* @param method request method
* @return error details string. Example: <pre>404 Not Found after GET http://example.com:8080/my-endpoint : [{'id': 123, 'message': 'my very long... (500 bytes)]</code></pre>
*/
@Override
@NotNull
public String getErrorDetails(int rawStatusCode, String statusText, @Nullable byte[] responseBody,
@Nullable Charset responseCharset, @Nullable URI url, @Nullable HttpMethod method) {
if (url == null || method == null) {
return getSimpleErrorDetails(rawStatusCode, statusText);
}
return getCompleteErrorDetails(rawStatusCode, statusText, responseBody, responseCharset, url, method);
}
@NotNull
private String getCompleteErrorDetails(int rawStatusCode, String statusText, @Nullable byte[] responseBody,
@Nullable Charset responseCharset, @Nullable URI url, @Nullable HttpMethod method) {
StringBuilder result = new StringBuilder();
result.append(getSimpleErrorDetails(rawStatusCode, statusText))
.append(" after ")
.append(method)
.append(" ")
.append(url)
.append(" : ");
if (responseBody == null || responseBody.length == 0) {
result.append("[no body]");
}
else {
result
.append("[")
.append(getResponseBody(responseBody, responseCharset))
.append("]");
}
return result.toString();
}
@NotNull
private String getSimpleErrorDetails(int rawStatusCode, String statusText) {
return rawStatusCode + " " + statusText;
}
private String getResponseBody(byte[] responseBody, @Nullable Charset responseCharset) {
Charset charset = getCharsetOrDefault(responseCharset);
if (responseBody.length < MAX_BODY_BYTES_LENGTH) {
return getCompleteResponseBody(responseBody, charset);
}
return getResponseBodyPreview(responseBody, charset);
}
@NotNull
private String getCompleteResponseBody(byte[] responseBody, Charset responseCharset) {
return new String(responseBody, responseCharset);
}
private String getResponseBodyPreview(byte[] responseBody, Charset responseCharset) {
try {
String bodyPreview = readBodyAsString(responseBody, responseCharset);
return bodyPreview + "... (" + responseBody.length + " bytes)";
}
catch (IOException e) {
// should never happen
throw new IllegalStateException(e);
}
}
@NotNull
private String readBodyAsString(byte[] responseBody, Charset responseCharset) throws IOException {
Reader reader = new InputStreamReader(new ByteArrayInputStream(responseBody), responseCharset);
CharBuffer result = CharBuffer.allocate(MAX_BODY_CHARS_LENGTH);
reader.read(result);
reader.close();
result.flip();
return result.toString();
}
private Charset getCharsetOrDefault(@Nullable Charset responseCharset) {
if (responseCharset == null) {
return StandardCharsets.ISO_8859_1;
}
return responseCharset;
}
}