Spring RestTemplate中getResponseBodyAsString返回乱码问题求助
解决RestTemplate捕获HttpClientErrorException后响应体乱码问题
问题原因
响应头包含Content-Encoding: gzip,说明服务器返回的错误响应体是gzip压缩格式,但HttpClientErrorException的getResponseBodyAsString()方法默认不会自动解压gzip内容,直接读取压缩后的字节流就会出现乱码。Postman能正常显示是因为它默认支持自动识别并解压gzip响应。
解决方案
方法一:手动解压异常响应体
直接从异常中获取原始字节数组,判断是否为gzip压缩后手动解压:
catch(HttpStatusCodeException he) { log.error("Exception Status: {} - {}", he.getStatusCode(), he.getStatusText()); log.error("Exception - header {} ", he.getResponseHeaders()); try { byte[] responseBody = he.getResponseBodyAsByteArray(); String decodedMsg; // 检查响应是否为gzip压缩 if ("gzip".equalsIgnoreCase(he.getResponseHeaders().getFirst(HttpHeaders.CONTENT_ENCODING))) { try (GzipInputStream gzipIn = new GzipInputStream(new ByteArrayInputStream(responseBody))) { decodedMsg = new String(gzipIn.readAllBytes(), StandardCharsets.UTF_8); } } else { // 非压缩情况直接转字符串 decodedMsg = new String(responseBody, StandardCharsets.UTF_8); } log.error("Exception - message {} ", decodedMsg); } catch (IOException e) { log.error("Failed to decode response body", e); } }
方法二:配置RestTemplate自动处理压缩
提前配置RestTemplate,让它自动发送支持gzip的请求头,并自动解压所有响应(包括异常响应):
@Bean public RestTemplate restTemplate() { RestTemplate restTemplate = new RestTemplate(); // 添加请求头,告知服务器可接收gzip压缩响应 restTemplate.getInterceptors().add((request, body, execution) -> { request.getHeaders().add(HttpHeaders.ACCEPT_ENCODING, "gzip"); return execution.execute(request, body); }); // 配置请求工厂,启用自动解压 SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory(); restTemplate.setRequestFactory(new BufferingClientHttpRequestFactory(new GzipHandlingRequestFactory(factory))); return restTemplate; } // 自定义请求工厂,实现响应自动解压 class GzipHandlingRequestFactory extends SimpleClientHttpRequestFactory { private final ClientHttpRequestFactory delegate; public GzipHandlingRequestFactory(ClientHttpRequestFactory delegate) { this.delegate = delegate; } @Override protected ClientHttpResponse createResponse(HttpURLConnection connection, String httpMethod) throws IOException { return new GzipHandlingResponse(super.createResponse(connection, httpMethod)); } private static class GzipHandlingResponse implements ClientHttpResponse { private final ClientHttpResponse delegate; public GzipHandlingResponse(ClientHttpResponse delegate) { this.delegate = delegate; } @Override public InputStream getBody() throws IOException { InputStream body = delegate.getBody(); String encoding = delegate.getHeaders().getFirst(HttpHeaders.CONTENT_ENCODING); if ("gzip".equalsIgnoreCase(encoding)) { return new GzipInputStream(body); } return body; } // 以下方法直接委托给原始响应实现 @Override public HttpHeaders getHeaders() { return delegate.getHeaders(); } @Override public HttpStatus getStatusCode() throws IOException { return delegate.getStatusCode(); } @Override public int getRawStatusCode() throws IOException { return delegate.getRawStatusCode(); } @Override public String getStatusText() throws IOException { return delegate.getStatusText(); } @Override public void close() { delegate.close(); } } }
配置完成后,无论是正常响应还是异常响应,RestTemplate都会自动处理gzip压缩,调用getResponseBodyAsString()时就能直接得到正常的JSON字符串。
内容的提问来源于stack exchange,提问作者Mayur
相关产品推荐
相关产品推荐

