在使用 Apache HttpClient 时,如果调用 HttpRequest.execute()
抛出了异常,通常情况下,异常不会直接包含完整的 response entity
。特别是当服务器返回错误响应(如 4xx 或 5xx 状态码)时,execute()
方法可能抛出各种类型的 IOException
或 HttpResponseException
,但这些异常并不一定会携带完整的 response body
。
Apache HttpClient 在抛出异常时,通常只会传递有关错误状态的信息(如 HTTP 状态码),而不会包装 response entity
。为了从错误响应中提取 response body
,你需要手动处理响应,即使发生了异常。
1. 捕获 HttpResponseException
HttpResponseException
是 Apache HttpClient 抛出的常见异常之一,它可以提供 HTTP 状态码,但默认情况下,它不会包含 response entity
。你可以通过捕获 HttpResponseException
来处理状态码相关的错误。
try {
CloseableHttpResponse response = httpClient.execute(request);
// 正常处理
} catch (HttpResponseException e) {
// 捕获状态码错误
System.out.println("HTTP Status Code: " + e.getStatusCode());
} catch (IOException e) {
// 其他IO异常处理
e.printStackTrace();
}
然而,HttpResponseException
并不会自动将 response entity
包装在异常中。因此,我们需要另一种方式来在抛出异常时访问 response entity
。
2. 如何获取异常中的 response entity
要捕获并读取异常中的 response entity
,你可以直接处理响应对象,即使请求导致了异常(如 4xx 或 5xx 错误),并在捕获异常之前手动检查 response
是否有内容可供读取。可以使用 HttpClient
的低级 API 来在异常发生时处理响应体。
3. 使用 responseHandler
捕获 response entity
Apache HttpClient 提供了一种机制——通过 ResponseHandler
可以捕获响应体,即使响应是错误的。通过使用 ResponseHandler
,你可以自己定义如何处理成功的响应和错误的响应,并在错误的情况下获取 response entity
。
示例代码:使用 ResponseHandler
获取错误响应体
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import java.io.IOException;
public class HttpClientExample {
public static void main(String[] args) {
String url = "https://example.com/api";
CloseableHttpClient httpClient = HttpClients.createDefault();
try {
HttpGet request = new HttpGet(url);
// 使用 ResponseHandler 来处理响应
ResponseHandler<String> responseHandler = new ResponseHandler<String>() {
@Override
public String handleResponse(final HttpResponse response) throws IOException {
int status = response.getStatusLine().getStatusCode();
if (status >= 200 && status < 300) {
HttpEntity entity = response.getEntity();
return entity != null ? EntityUtils.toString(entity) : null;
} else {
// 错误情况下捕获response body
HttpEntity entity = response.getEntity();
String errorResponse = entity != null ? EntityUtils.toString(entity) : null;
throw new ClientProtocolException("Unexpected response status: " + status +
", response body: " + errorResponse);
}
}
};
// 这里使用自定义的 ResponseHandler 来执行请求并处理响应
String responseBody = httpClient.execute(request, responseHandler);
System.out.println(responseBody);
} catch (ClientProtocolException e) {
// 捕获并打印异常中的 response body
System.out.println("Exception caught: " + e.getMessage());
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
httpClient.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
关键点说明:
ResponseHandler
:通过自定义的ResponseHandler
,你可以在错误响应(如 4xx 或 5xx)时,捕获并读取response entity
,而不是让execute()
方法直接抛出异常。- 错误处理:在
ResponseHandler
中处理状态码大于等于 400 的响应,并将response entity
转换为String
,即使抛出异常,也可以从异常中获取到响应体。 ClientProtocolException
:在异常中,你可以访问状态码以及响应体。
4. 捕获 HttpEntity
并处理异常响应
如果不想使用 ResponseHandler
,你可以在捕获异常之前直接获取 CloseableHttpResponse
并检查是否存在 response entity
,然后手动读取。
示例代码:手动捕获 response entity
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import java.io.IOException;
public class HttpClientExample {
public static void main(String[] args) {
String url = "https://example.com/api";
CloseableHttpClient httpClient = HttpClients.createDefault();
CloseableHttpResponse response = null;
try {
HttpGet request = new HttpGet(url);
response = httpClient.execute(request);
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode >= 200 && statusCode < 300) {
HttpEntity entity = response.getEntity();
String responseBody = entity != null ? EntityUtils.toString(entity) : null;
System.out.println("Response Body: " + responseBody);
} else {
// 处理错误响应,获取错误的 response body
HttpEntity entity = response.getEntity();
String errorResponse = entity != null ? EntityUtils.toString(entity) : null;
System.out.println("Error Response Body: " + errorResponse);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (response != null) {
response.close();
}
httpClient.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
关键点:
- 手动管理
CloseableHttpResponse
,即使在出现异常时,也可以手动读取response entity
。 - 在错误响应时,通过
response.getEntity()
手动获取并读取错误的响应体。
总结:
- Apache HttpClient 抛出的异常,如
HttpResponseException
,不会自动包含response entity
。如果你想在异常中获取到response entity
,最好的做法是使用ResponseHandler
或在捕获异常前手动处理响应对象。 - 通过自定义的
ResponseHandler
,你可以在请求抛出异常时依然获取到完整的response body
。