Java客户端向Apache发送GZIP压缩请求报400错误求助
双向HTTP Gzip压缩请求报错排查与解决
问题现象
需要通过Gzip内容编码HTTP头实现请求与响应的双向HTTP流量压缩:
- 已实现接收并解压Apache HTTP Server返回的压缩数据
- 向服务器发送GZIP格式的压缩请求时,收到
400 Bad Request错误,Apache日志显示:AH01387: Zlib: Invalid header
Java客户端代码
public class HttpClientTester extends StandaloneApplication { public static byte[] deflate(byte[] input) { Deflater deflater = new Deflater(); deflater.setLevel(9); deflater.setInput(input); deflater.finish(); ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); byte[] buffer = new byte[1024]; while (!deflater.finished()) { int compressedSize = deflater.deflate(buffer); outputStream.write(buffer, 0, compressedSize); } return outputStream.toByteArray(); } public static byte[] compress(byte[] input) throws IOException { ByteArrayOutputStream byteStream = new ByteArrayOutputStream(); GZIPOutputStream zipStream = new GZIPOutputStream(byteStream); zipStream.write(input); zipStream.flush(); zipStream.finish(); zipStream.close(); return byteStream.toByteArray(); } public static String deflateReverse(byte[] input) throws DataFormatException, UnsupportedEncodingException { Inflater inflater = new Inflater(); inflater.setInput(input); ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); byte[] buffer = new byte[1024]; while (!inflater.finished()) { int decompressedSize = inflater.inflate(buffer); outputStream.write(buffer, 0, decompressedSize); } return new String(outputStream.toByteArray(), "UTF-8"); } public static String decompress(byte[] input) throws IOException { GZIPInputStream zippedInputStream = new GZIPInputStream(new ByteArrayInputStream(input)); return Tools.readStream(zippedInputStream, StandardCharsets.UTF_8); } @Override public Void execute(StandaloneApplicationContext arg0) throws Exception { Bundle sslProperties = new Bundle(); sslProperties.set(SSLProperties.SSL_VERSION, "TLSv1.2"); sslProperties.set(SSLProperties.SSL_TRUST_ALL_CERTS, true); HTTPSHandler httpsHandler = new HTTPSHandler(null, arg0.getLoggingContext().getLoggingId(), sslProperties); HttpClientV2 clientV2 = new HttpClientV2(null, arg0.getLoggingContext().getLoggingId(), arg0.getConfigurationContext().getParametersReader()); clientV2.setSSLHandler(httpsHandler); HttpRequest httpRequest = HttpFactory.createHttpRequest(HttpConstants.HTTP_CONTENT_TYPE_TEXT_HTML); httpRequest.setTransactionId(arg0.getLoggingContext().getLoggingId()); httpRequest.setHeaderField("Accept-encoding", "gzip"); httpRequest.setHeaderField("Content-encoding", "gzip"); httpRequest.setURL("https://myserver/myapp"); httpRequest.setMethod(HttpMethod.POST); byte[] unzippedInputBody = "<MessageEnvelop><Type>ERROR</Type><Anomaly>ERROR WHILE PARSING XML REQUEST</Anomaly></MessageEnvelop>".getBytes("UTF-8"); byte[] zippedInputBody = compress(unzippedInputBody); httpRequest.setBody(zippedInputBody); httpRequest.setHeaderField("content-length", "" + zippedInputBody.length); HttpResponse httpResponse = clientV2.doCommunication(httpRequest); byte[] stream = httpResponse.getBodyStream(); String data = decompress(stream); //@formatter:off pause( "Data length.........: " + stream.length + "\n"+ "Real data...........: " + data + "\n"+ "Response B64 data...: " + new Base64().encode(stream) + "\n"+ "Request B64 data....: " + new Base64().encode(zippedInputBody)); //@formatter:on return null; } public static void main(String[] args) { StandaloneApplicationContext.run(new HttpClientTester()); } }
Apache VirtualHost配置
SetInputFilter DEFLATE SetOutputFilter DEFLATE
相关压缩数据(Base64格式)
H4sIAAAAAAAAALPxTS0uTkxPdc0rS83JL7CzCaksSLVzDQryD7LRB7NtHPPycxNzKiGCCuEenj6uCgGOQcGefu4KEb4+CkGugaGuwSE2+jCFNvpohgIA/IH0c2UAAAA=
问题原因
Apache的SetInputFilter DEFLATE过滤器期望接收的是纯DEFLATE格式的压缩数据,而非GZIP格式:
- GZIP格式在DEFLATE压缩流基础上,额外添加了10字节的头部(包含标识、压缩方法等)和8字节的尾部(CRC32校验值、原始数据长度)
- 客户端通过
GZIPOutputStream生成的是完整GZIP格式数据,不符合Apache输入过滤器的解析要求,因此触发"无效头"错误
解决方案
方案1:修改客户端使用DEFLATE格式压缩请求(推荐)
- 使用现有
deflate方法生成纯DEFLATE压缩流,替换原compress方法的调用 - 将请求头
Content-Encoding改为deflate(匹配Apache过滤器的期望)
修改后的execute方法关键部分:
// 替换压缩逻辑为deflate方法 byte[] zippedInputBody = deflate(unzippedInputBody); // 修改Content-Encoding头 httpRequest.setHeaderField("Content-encoding", "deflate");
方案2:修改Apache配置支持GZIP格式请求(复杂)
Apache原生DEFLATE输入过滤器不支持GZIP格式,需通过以下方式实现:
- 安装第三方模块(如
mod_gzip,但已停止维护) - 编写自定义Apache模块或使用Lua脚本解析GZIP格式请求
此方案复杂度高,不推荐用于简单场景。
内容的提问来源于stack exchange,提问作者Francesco Rizzi
相关产品推荐
相关产品推荐

