You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring WebClient解码gzip分块响应时StringDecoder乱码如何解决

问题根因

乱码和chunked分块传输没有直接关系,核心原因是响应开启了gzip压缩,但你使用的WebClient实例没有开启gzip自动解压能力,StringDecoder直接拿到压缩后的二进制字节流按字符串规则解码,就会输出你看到的乱码内容。
从你贴出的响应头可以看到明确的Content-Encoding: gzip标识,说明返回的内容是gzip压缩后的二进制数据,并非原始的JSON明文。

解决方案

按需选择以下任意一种方案处理即可:

方案1:全局开启WebClient的gzip自动解压(推荐)

构造WebClient实例时,在底层客户端配置中开启gzip响应自动解压能力,框架会自动识别Content-Encoding: gzip响应头,先完成解压操作再把明文内容交给后续解码器处理,不需要修改已有的业务调用代码。
如果使用的是默认Reactor Netty客户端实现的WebClient,配置代码如下:

WebClient client = WebClient.builder()
        .clientConnector(new ReactorClientHttpConnector(
                HttpClient.create()
                        // 开启gzip、deflate等压缩格式自动解压
                        .compress(true)
        ))
        .build();

配置完成后原有调用逻辑不需要做任何调整,就能正常拿到解压后的JSON字符串。

方案2:单次请求手动处理gzip解压

如果不方便修改全局WebClient配置,可以在单次请求中先获取原始字节流,手动完成gzip解压后再转成字符串:

Mono<ResponseEntity<String>> response = client.get().uri(url)
        .retrieve()
        .onStatus(HttpStatus::isError, t -> Mono.empty())
        // 先获取原始字节数组,不要直接转String
        .toEntity(byte[].class)
        .map(entity -> {
            HttpHeaders headers = entity.getHeaders();
            byte[] body = entity.getBody();
            String resultContent;
            // 校验响应是否为gzip压缩内容
            if (body != null && "gzip".equals(headers.getFirst(HttpHeaders.CONTENT_ENCODING))) {
                try (GZIPInputStream gzipInputStream = new GZIPInputStream(new ByteArrayInputStream(body));
                     ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
                    byte[] buffer = new byte[1024];
                    int readLen;
                    while ((readLen = gzipInputStream.read(buffer)) > 0) {
                        outputStream.write(buffer, 0, readLen);
                    }
                    // 可根据接口实际编码调整,绝大多数场景用UTF-8即可
                    resultContent = outputStream.toString(StandardCharsets.UTF_8);
                } catch (IOException e) {
                    throw new RuntimeException("响应gzip解压失败", e);
                }
            } else {
                resultContent = new String(body == null ? new byte[0] : body, StandardCharsets.UTF_8);
            }
            return new ResponseEntity<>(resultContent, headers, entity.getStatusCode());
        });
注意事项
  • Transfer-Encoding: chunked代表HTTP分块传输编码,属于传输层的内容分段传输规则,WebClient底层默认就支持处理分块传输,不需要额外配置,不要被这个响应头误导排查方向。
  • 不要尝试先把压缩后的字节流转成字符串再做解压,字节转字符串的过程中会因为编码匹配问题丢失字节信息,直接导致后续解压失败,必须在字节流层面完成解压操作后再转成明文字符串。
  • 你贴出的示例调用代码里.retrieve();末尾多了一个多余的分号,会触发编译错误,实际运行时记得删掉。

内容的提问来源于stack exchange,提问作者cool_ravi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 20:36:10