Java 客户端 + Apache HTTP 服务器 + GZIP 压缩/解压缩

问题描述 投票:0回答:1

我想通过 gzip 内容编码 http 标头来压缩请求和响应上的 HTTP 流量。我能够从 HTTP 服务器接收压缩数据并解压缩它,但是如果我尝试使用 gzip 格式压缩数据并将这些数据发送到 HTTP 服务器,我会收到 400 Bad Request,在 Apache 日志中我可以看到:

AH01387:Zlib:无效标头

我有以下代码:

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 + "\r\n"+ 
            "Real data...........: " + data + "\r\n"+
            "Response B64 data...: " + new Base64().encode(stream) + "\r\n"+
            "Request B64 data....: " + new Base64().encode(zippedInputBody));
        //@formatter:on
        return null;
    }

    public static void main(String[] args) {
        StandaloneApplicationContext.run(new HttpClientTester());
    }
}

我已在 VirtualHost 中使用以下设置设置 Apache HTTP 服务器:

SetInputFilter DEFLATE
SetOutputFilter DEFLATE

目标是压缩整个流量(请求和响应)。现在我可以在 Apache HTTP 服务器接收到数据时对其进行解压缩。 目前未压缩的数据是以下字符串:

<MessageEnvelop><Type>ERROR</Type><Anomaly>ERROR WHILE PARSING XML REQUEST</Anomaly></MessageEnvelop>

GZIP 压缩(B64)数据,当前用于请求和响应,请注意,数据以二进制格式发送,base64 格式用于比较我的压缩流和接收到的流:

H4sIAAAAAAAAALPxTS0uTkxPdc0rS83JL7CzCaksSLVzDQryD7LRB7NtHPPycxNzKiGCCuEenj6uCgGOQcGefu4KEb4+CkGugaGuwSE2+jCFNvpohgIA/IH0c2UAAAA=

当 Web 应用程序收到无效的 XML 请求时,会收到当前的 XML。如果没有对 HTTP 请求进行 GZIP 压缩,我就能够接收压缩后的文件,并能够在我的 Java 客户端中对其进行解压缩。如果我也尝试压缩我的请求,我会从 HTTP 服务器收到 400 个错误请求,而没有任何机会访问我的 Web 应用程序。

附上Java客户端日志导出的交互消息:

留言

java apache http gzip zlib
1个回答
0
投票

以上全部正确。问题出在使用的 HttpClient 对象中。它将 gzip 数据作为字符串而不是字节数组进行操作。 修复了HTTP请求体的管理后,就不再出现问题了。

谢谢。

© www.soinside.com 2019 - 2024. All rights reserved.