我想通过 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客户端日志导出的交互消息:
以上全部正确。问题出在使用的 HttpClient 对象中。它将 gzip 数据作为字符串而不是字节数组进行操作。 修复了HTTP请求体的管理后,就不再出现问题了。
谢谢。