使用RestTemplate打印异常时如何输出完整的错误响应信息?
RestTemplate调用HTTP接口错误响应体截断问题
问题背景
我们的应用基于Spring Boot 2.3.10.RELEASE版本开发,通过RestTemplate调用大量REST API。当接口返回4xx或5xx类HTTP错误码并携带响应体时,日志中无法输出完整的响应体内容。
最小可复现示例
import lombok.extern.slf4j.Slf4j; import org.junit.jupiter.api.Test; import org.springframework.web.client.HttpClientErrorException; import org.springframework.web.client.RestTemplate; @Slf4j public class RestTemplateTest { @Test void shouldPrintErrorForRestTemplate() { RestTemplate restTemplate = new RestTemplate(); try { restTemplate.getForEntity("http://hellosmilep.free.beeceptor.com/error/notfound", String.class); } catch (Exception e) { log.error("Error calling REST API", e); } } }
实际日志输出
10:28:11.347 [main] ERROR com.smilep.java.webapp.RestTemplateTest - Error calling REST API org.springframework.web.client.HttpClientErrorException$NotFound: 404 Not Found: [{ "glossary": { "title": "example glossary", "GlossDiv": { "title": "S", "GlossList": { "GlossEntry": { "ID": "SGML", "SortAs": "SGML", "Glo... (593 bytes)] ...(堆栈省略)
现有方案痛点
目前可以通过如下代码手动打印完整响应体,但需要在大量业务类中添加重复的样板代码,跨应用适配成本很高:
if(e instanceof HttpClientErrorException) { log.error("response body : " + ((HttpClientErrorException) e).getResponseBodyAsString()); }
疑问点
- 有没有办法在直接打印Exception对象时就输出完整的错误响应体,不会出现
... (xxx bytes)的截断? - Java中是否存在默认的错误日志消息长度限制,超过就会自动截断?如果有,如何修改该限制?
相关更新
已向Spring团队提交Issue建议将该日志长度限制改为可配置项,目前官方已完全移除该限制,改动将在后续Spring版本上线。
问题解答
1. 截断的根本原因
Java本身的日志框架(SLF4J、Logback、Log4j2等)默认没有异常消息长度限制,该截断是Spring框架RestTemplate的内部实现导致的:HttpClientErrorException/HttpServerErrorException构造异常消息时,默认只会读取前200字节的响应体拼接到message字段,超出部分就会生成... (xxx bytes)的截断提示,因此直接打印异常时看不到完整内容。
2. 无需修改业务代码的全局解决方案
通过自定义全局ResponseErrorHandler就可以实现直接打印异常就输出完整响应体,适配所有使用RestTemplate的业务场景,步骤如下:
- 实现自定义错误处理器,捕获异常时用完整响应体重写异常消息:
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatusCode; import org.springframework.http.client.ClientHttpResponse; import org.springframework.web.client.DefaultResponseErrorHandler; import org.springframework.web.client.HttpClientErrorException; import org.springframework.web.client.HttpServerErrorException; import java.io.IOException; import java.nio.charset.StandardCharsets; public class FullResponseBodyErrorHandler extends DefaultResponseErrorHandler { @Override public void handleError(ClientHttpResponse response) throws IOException { // 读取完整响应体 byte[] body = getResponseBody(response); String responseBody = new String(body, StandardCharsets.UTF_8); HttpStatusCode statusCode = response.getStatusCode(); String statusText = response.getStatusText(); HttpHeaders headers = response.getHeaders(); try { super.handleError(response); } catch (HttpClientErrorException | HttpServerErrorException e) { // 抛出带完整响应体的新异常,覆盖原有截断消息 if (e instanceof HttpClientErrorException) { throw new HttpClientErrorException(statusCode, statusText + ": " + responseBody, headers, body, StandardCharsets.UTF_8); } else { throw new HttpServerErrorException(statusCode, statusText + ": " + responseBody, headers, body, StandardCharsets.UTF_8); } } } }
- Spring Boot项目中全局配置RestTemplate使用该错误处理器:
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.client.RestTemplate; @Configuration public class RestTemplateConfig { @Bean public RestTemplate restTemplate() { RestTemplate restTemplate = new RestTemplate(); restTemplate.setErrorHandler(new FullResponseBodyErrorHandler()); return restTemplate; } }
配置完成后,所有通过依赖注入获取的RestTemplate抛出的HTTP异常都会携带完整响应体,业务代码直接打印异常就可以看到完整内容,不需要做任何修改。
3. 官方版本适配方案
Spring官方移除响应体截断限制的改动已经在Spring Framework 5.3.22+、6.0.0+版本正式生效,升级Spring Boot版本到2.7.2+或者3.x及以上版本,默认就不会出现响应体截断问题,不需要额外配置。
内容的提问来源于stack exchange,提问作者Smile
相关产品推荐
相关产品推荐

