gzip/deflate 使用 tomcat servlet 上的服务器发送事件进行压缩
gzip/deflate compression with Server Sent Events on tomcat servlet
我正在使用服务器发送的事件进行流式响应 (text/event-stream)。我们想使用 gzip 或 deflate 压缩来压缩响应,但浏览器显示:ERR_CONTENT_DECODING_FAILED。
相同的代码 -
response.setContentType("text/event-stream; charset=UTF-8");
response.addHeader("Connection", "keep-alive");
response.addHeader("Cache-Control", "no-cache, must-revalidate");
response.addHeader("Content-Encoding", "deflate");
PrintWriter writer = response.getWriter();
number = 10;
time = 100;
for (int i = 0; i < number; i++) {
String resp = "data: " + "Some Response" + "\r\n";
Deflater deflater = new Deflater(Deflater.DEFLATED);
byte[] input = resp.getBytes("UTF-8");
deflater.setInput(input);
deflater.finish();
byte[] output = new byte[1024];
deflater.deflate(output);
deflater.end();
writer.write(new String(output, "UTF-8"));
writer.flush();
try {
Thread.sleep(time);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
String resp = "data: close\r\n";
Deflater deflater = new Deflater(Deflater.DEFLATED);
byte[] input = resp.getBytes("UTF-8");
deflater.setInput(input);
deflater.finish();
byte[] output = new byte[1024];
deflater.deflate(output);
deflater.end();
writer.write(new String(output, "UTF-8"));
writer.flush();
- 压缩流是二进制数据。不得打印
response.getWriter()
。请改用 response.getOutputStream()
。
更新
Shiva Bhalla: Using the response.getOutputStream() with text/event-stream isn't doing proper streaming after the 1st chunk of response is displayed, the request is being failed at the browser.
您必须使用单个 Deflater 实例压缩整个流。
在您的代码中,您分别压缩了每个片段。这相当于以下内容:
- 您获取了一系列文本文件(01.txt、02.txt、...)。
- 您将它们中的每一个都压缩到 gzip 存档中。 (01.txt.gz, 02.txt.gz, ...)
- 您将档案连接成一个文件。
以上生成的存档不正确。 Gzip 文件不能像那样连接。正确的代码应该执行以下操作:
- 您获取了一系列文本文件(01.txt、02.txt、...)。
- 您将文本文件连接成一个文件 (text.txt)。
- 您将文件压缩为 gzip 存档。 (text.txt.gz)
我建议您使用 java.util.zip.DeflaterOutputStream
(1) 而不是直接使用 Deflater
。例如
new DeflaterOutputStream(response.getOutputStream(), true);
谨防引入 BREACH 漏洞。
在连接器属性中将 "text/event-stream;charset=UTF-8,ms-stream;charset=UTF-8" 添加为 "compressableMimeType" 完成了工作!
我正在使用服务器发送的事件进行流式响应 (text/event-stream)。我们想使用 gzip 或 deflate 压缩来压缩响应,但浏览器显示:ERR_CONTENT_DECODING_FAILED。 相同的代码 -
response.setContentType("text/event-stream; charset=UTF-8");
response.addHeader("Connection", "keep-alive");
response.addHeader("Cache-Control", "no-cache, must-revalidate");
response.addHeader("Content-Encoding", "deflate");
PrintWriter writer = response.getWriter();
number = 10;
time = 100;
for (int i = 0; i < number; i++) {
String resp = "data: " + "Some Response" + "\r\n";
Deflater deflater = new Deflater(Deflater.DEFLATED);
byte[] input = resp.getBytes("UTF-8");
deflater.setInput(input);
deflater.finish();
byte[] output = new byte[1024];
deflater.deflate(output);
deflater.end();
writer.write(new String(output, "UTF-8"));
writer.flush();
try {
Thread.sleep(time);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
String resp = "data: close\r\n";
Deflater deflater = new Deflater(Deflater.DEFLATED);
byte[] input = resp.getBytes("UTF-8");
deflater.setInput(input);
deflater.finish();
byte[] output = new byte[1024];
deflater.deflate(output);
deflater.end();
writer.write(new String(output, "UTF-8"));
writer.flush();
- 压缩流是二进制数据。不得打印
response.getWriter()
。请改用response.getOutputStream()
。
更新
Shiva Bhalla: Using the response.getOutputStream() with text/event-stream isn't doing proper streaming after the 1st chunk of response is displayed, the request is being failed at the browser.
您必须使用单个 Deflater 实例压缩整个流。
在您的代码中,您分别压缩了每个片段。这相当于以下内容:
- 您获取了一系列文本文件(01.txt、02.txt、...)。
- 您将它们中的每一个都压缩到 gzip 存档中。 (01.txt.gz, 02.txt.gz, ...)
- 您将档案连接成一个文件。
以上生成的存档不正确。 Gzip 文件不能像那样连接。正确的代码应该执行以下操作:
- 您获取了一系列文本文件(01.txt、02.txt、...)。
- 您将文本文件连接成一个文件 (text.txt)。
- 您将文件压缩为 gzip 存档。 (text.txt.gz)
我建议您使用
java.util.zip.DeflaterOutputStream
(1) 而不是直接使用Deflater
。例如new DeflaterOutputStream(response.getOutputStream(), true);
谨防引入 BREACH 漏洞。
在连接器属性中将 "text/event-stream;charset=UTF-8,ms-stream;charset=UTF-8" 添加为 "compressableMimeType" 完成了工作!