RestTemplate exchange调用返回403错误时响应体为空问题
问题根因
这个问题是RestTemplate默认HTTP客户端的历史遗留行为导致的,和服务端逻辑无关:
- RestTemplate默认使用
SimpleClientHttpRequestFactory构建HTTP请求,底层依赖JDK自带的HttpURLConnection实现 - JDK的
HttpURLConnection内置了HTTP认证流程的默认处理逻辑:当收到401、403这类属于认证授权范畴的错误状态码时,会默认判定响应属于认证质询,主动丢弃响应体内容,不会把完整响应透传给上层的RestTemplate,因此你捕获到的HttpClientErrorException中响应体为空 - Postman、curl等独立HTTP客户端没有内置这个拦截逻辑,因此可以正常读取到服务端返回的JSON内容
另外你贴出的服务端代码存在两处配置错误,会导致异常处理不生效:
@ExceptionHandler(CustomException.class)声明捕获的异常类型是CustomException,但方法入参却是OperationNotAllowed类型,异常类型不匹配会导致这个处理方法根本不会被触发- 该处理方法硬编码返回401状态码,和你描述的403错误场景不匹配,说明服务端存在其他返回403的分支,没有走到你自定义的异常处理逻辑中
修复方案
1. 替换RestTemplate底层HTTP客户端(优先推荐)
将RestTemplate的底层实现替换为Apache HttpComponents Client或者OkHttp,这两个客户端不会主动拦截吞掉401/403的响应体,不需要修改原有业务逻辑。
以Apache HttpClient为例,初始化RestTemplate时指定客户端工厂即可:
// 替换默认的SimpleClientHttpRequestFactory RestTemplate restTemplate = new RestTemplate(new HttpComponentsClientHttpRequestFactory());
替换后所有状态码的响应体都会被完整读取,原有异常分支读取响应JSON的逻辑可以正常工作。
2. 修正服务端异常处理配置
- 对齐
@ExceptionHandler注解声明的异常类型和方法入参的异常类型,要捕获OperationNotAllowed异常就将注解改为@ExceptionHandler(OperationNotAllowed.class) - 排查服务端所有返回403状态码的逻辑,确保所有错误分支都被全局异常处理器拦截,统一返回JSON格式响应,避免走Spring Boot默认的错误页返回逻辑(默认错误页在请求头不接受
text/html时可能返回空响应体)
3. 临时兼容方案(不推荐)
如果暂时无法替换HTTP客户端,可以通过设置JDK系统属性关闭HttpURLConnection的自动认证拦截逻辑:
// 禁用HttpURLConnection的自动认证处理 sun.net.www.protocol.http.HttpURLConnection.setHasAuthenticator(false);
该方案依赖JDK内部私有API,不同版本JDK兼容性差,仅作临时调试使用。
内容的提问来源于stack exchange,提问作者iCode
相关产品推荐
相关产品推荐

