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

通过CURL向RESTful PUT发送.gz文件触发ZipException问题求助

解决Spring Boot + Jersey PUT接口接收GZIP文件时的ZipException问题

Hey,我之前也碰到过几乎一模一样的问题!单元测好好的,一用curl发请求就炸ZipException,排查下来确实是服务器把二进制GZIP数据当成UTF-8字符解析,把非UTF-8字节替换成了EF BF BD,直接破坏了GZIP的格式。结合Spring Boot + Jersey的特性,给你几个靠谱的解决思路:

核心原因

JAX-RS(Jersey)默认情况下,如果没有明确指定请求体的处理方式,可能会把输入流按字符流来解析——哪怕你参数用的是InputStream。这种字符编码转换(默认UTF-8)会把GZIP里的二进制字节搞坏,自然解压失败。

解决方案(按优先级尝试)

1. 给接口加@Consumes注解明确媒体类型

这是最直接的方法,告诉Jersey我们要接收的是application/gzip类型的二进制数据,别瞎搞字符编码:

public class Service { 
    @PUT 
    @Path("/{filename}")
    @Consumes("application/gzip") // 关键!指定接收二进制GZIP
    Response doPut(@Context HttpServletRequest request, 
                   @PathParam("filename") String filename, 
                   InputStream inputStream) { 
        try { 
            GZIPInputStream gzipInputStream = new GZIPInputStream(inputStream); 
            // 你的处理逻辑
        } catch (IOException e) { 
            e.printStackTrace();
            return Response.serverError().entity("解压失败").build(); // 别返回null,返回合法响应
        } 
        return Response.ok().build(); 
    } 
}

2. 换成byte[]作为请求体参数

有时候Jersey对byte[]的处理更“老实”,不会经过字符编码转换。试试把参数改成byte[],再转成流:

@PUT 
@Path("/{filename}")
@Consumes("application/gzip")
Response doPut(@Context HttpServletRequest request, 
               @PathParam("filename") String filename, 
               byte[] gzipBytes) { 
    try { 
        GZIPInputStream gzipInputStream = new GZIPInputStream(new ByteArrayInputStream(gzipBytes)); 
        // 处理逻辑
    } catch (IOException e) { 
        e.printStackTrace();
        return Response.serverError().build();
    } 
    return Response.ok().build(); 
}

3. 配置Jersey强制二进制处理

如果上面两种方法都不行,就得从Jersey的全局配置入手,禁用自动字符编码转换。创建一个ResourceConfig的子类:

import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.server.ServerProperties;
import org.springframework.context.annotation.Configuration;

@Configuration
public class JerseyConfig extends ResourceConfig {
    public JerseyConfig() {
        register(Service.class);
        // 禁用自动编码转换,强制按二进制处理请求体
        property(ServerProperties.MEDIA_TYPE_MAPPINGS, "gzip:application/gzip");
        // 确保Jersey不使用字符流读取请求
        property(ServerProperties.RESPONSE_SET_STATUS_OVER_SEND_ERROR, true);
    }
}

4. 排查Spring Boot的HttpMessageConverter干扰

如果你的项目同时用了Spring MVC和Jersey,Spring的HttpMessageConverter可能会抢着处理请求,把二进制转成字符。这时候可以试试排除Spring MVC的自动配置:

@SpringBootApplication(exclude = {WebMvcAutoConfiguration.class})
public class YourApplication {
    public static void main(String[] args) {
        SpringApplication.run(YourApplication.class, args);
    }
}

5. 再确认curl命令的正确性

你的curl命令其实是对的,但再强调一下:一定要用--data-binary参数,别用-d或--data,因为后两者会按表单编码处理数据,可能偷偷改你的二进制:

curl -v -k -X PUT --user USER:Password -H "Content-Type: application/gzip" --data-binary @testFile.gz https://myapp.dev.com/testFile.gz

验证小技巧

修改完后,你可以用hexdump对比原始文件和服务器接收到的内容:

# 查看原始GZIP文件的前16字节(GZIP的魔法数是1F 8B)
hexdump -n 16 testFile.gz

然后在服务器端打印输入流的前16字节,如果和上面的输出一致,说明数据没被损坏,解压肯定能正常运行。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 08:55:08