使用 GZIPOutputStream 在 java 中发送压缩块
Using GZIPOutputStream to send a compressed chunk in java
我试图通过 java 套接字发送一个压缩的 HTML 文件,但浏览器显示一个空的 HTML 文件。
问题是,当我尝试发送未压缩的 HTML 时,一切正常(是的,我确实相应地修改了 HTTP headers)。
private void sendResponse(String headers, String body) throws IOException
{
BufferedOutputStream output = new BufferedOutputStream(
this.SOCKET.getOutputStream());
byte[] byteBody = null;
// GZIP compression
if(body != null && this.encoding.contains("gzip"))
{
ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
GZIPOutputStream zipStream = new GZIPOutputStream(byteStream);
zipStream.write(body.getBytes(this.charset));
zipStream.flush();
byteBody = byteStream.toByteArray();
byteStream.flush();
byteStream.close();
zipStream.close();
}
else
byteBody = body.getBytes(this.charset);
// Sending response
byte[] msg1 = (Integer.toHexString(byteBody.length) + "\r\n")
.getBytes(this.charset);
byte[] msg2 = byteBody;
byte[] msg3 = ("\r\n" + "0").getBytes(this.charset);
output.write(headers.getBytes(this.charset));
output.write(msg1);
output.write(msg2);
output.write(msg3);
output.flush();
output.close();
}
基本上,headers 包含 HTTP headers,并且 body HTML 文件。其余的似乎不言自明。什么会导致这种行为?
编辑:header 是这样生成的:
headers = "HTTP/1.1 200 OK\r\n";
headers += "Date: " + WebServer.getServerTime(Calendar.getInstance()) + "\r\n";
headers += "Content-Type: text/html; charset=" + this.charset + "\r\n";
headers += "Set-Cookie: sessionID=" + newCookie + "; Max-Age=600\r\n";
headers += "Connection: close \r\n";
if(this.encoding.contains("gzip"))
headers += "Content-Encoding: gzip\r\n";
headers += "Transfer-Encoding: chunked \r\n";
headers += "\r\n";
一个简单的测试 class 应该会告诉您问题出在哪里:
import java.io.ByteArrayOutputStream;
import java.util.zip.GZIPOutputStream;
public class GZipTest {
public final static void main(String[] args) throws Exception {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
GZIPOutputStream gzos = new GZIPOutputStream(baos);
gzos.write("some data".getBytes());
System.out.println("baos before gzip flush: " + baos.size());
gzos.flush();
System.out.println("baos after gzip flush: " + baos.size());
gzos.close();
System.out.println("baos after gzip close: " + baos.size());
}
}
这将导致以下输出:
baos before gzip flush: 10
baos after gzip flush: 10
baos after gzip close: 29
您在构建正文数据后关闭 GZIPOutputStream
,因此浏览器收到不完整的 GZIP 数据,因此无法解压缩。
问题是调用了GZIPOutputStream
isn't complete until the finish()
方法。
当你close()
流时它会自动调用。
由于您是在 byteStream.toByteArray()
发生之前调用的,因此您没有获得完整的数据。
此外,您不需要调用 flush()
,因为当您调用 close()
时,它也会自动完成。关闭 GZIPOutputStream
会自动关闭底层流(即 ByteArrayOutputStream
)。
所以,你的代码应该是:
ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
GZIPOutputStream zipStream = new GZIPOutputStream(byteStream);
zipStream.write(body.getBytes(this.charset));
zipStream.close();
byteBody = byteStream.toByteArray();
我试图通过 java 套接字发送一个压缩的 HTML 文件,但浏览器显示一个空的 HTML 文件。
问题是,当我尝试发送未压缩的 HTML 时,一切正常(是的,我确实相应地修改了 HTTP headers)。
private void sendResponse(String headers, String body) throws IOException
{
BufferedOutputStream output = new BufferedOutputStream(
this.SOCKET.getOutputStream());
byte[] byteBody = null;
// GZIP compression
if(body != null && this.encoding.contains("gzip"))
{
ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
GZIPOutputStream zipStream = new GZIPOutputStream(byteStream);
zipStream.write(body.getBytes(this.charset));
zipStream.flush();
byteBody = byteStream.toByteArray();
byteStream.flush();
byteStream.close();
zipStream.close();
}
else
byteBody = body.getBytes(this.charset);
// Sending response
byte[] msg1 = (Integer.toHexString(byteBody.length) + "\r\n")
.getBytes(this.charset);
byte[] msg2 = byteBody;
byte[] msg3 = ("\r\n" + "0").getBytes(this.charset);
output.write(headers.getBytes(this.charset));
output.write(msg1);
output.write(msg2);
output.write(msg3);
output.flush();
output.close();
}
基本上,headers 包含 HTTP headers,并且 body HTML 文件。其余的似乎不言自明。什么会导致这种行为?
编辑:header 是这样生成的:
headers = "HTTP/1.1 200 OK\r\n";
headers += "Date: " + WebServer.getServerTime(Calendar.getInstance()) + "\r\n";
headers += "Content-Type: text/html; charset=" + this.charset + "\r\n";
headers += "Set-Cookie: sessionID=" + newCookie + "; Max-Age=600\r\n";
headers += "Connection: close \r\n";
if(this.encoding.contains("gzip"))
headers += "Content-Encoding: gzip\r\n";
headers += "Transfer-Encoding: chunked \r\n";
headers += "\r\n";
一个简单的测试 class 应该会告诉您问题出在哪里:
import java.io.ByteArrayOutputStream;
import java.util.zip.GZIPOutputStream;
public class GZipTest {
public final static void main(String[] args) throws Exception {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
GZIPOutputStream gzos = new GZIPOutputStream(baos);
gzos.write("some data".getBytes());
System.out.println("baos before gzip flush: " + baos.size());
gzos.flush();
System.out.println("baos after gzip flush: " + baos.size());
gzos.close();
System.out.println("baos after gzip close: " + baos.size());
}
}
这将导致以下输出:
baos before gzip flush: 10
baos after gzip flush: 10
baos after gzip close: 29
您在构建正文数据后关闭 GZIPOutputStream
,因此浏览器收到不完整的 GZIP 数据,因此无法解压缩。
问题是调用了GZIPOutputStream
isn't complete until the finish()
方法。
当你close()
流时它会自动调用。
由于您是在 byteStream.toByteArray()
发生之前调用的,因此您没有获得完整的数据。
此外,您不需要调用 flush()
,因为当您调用 close()
时,它也会自动完成。关闭 GZIPOutputStream
会自动关闭底层流(即 ByteArrayOutputStream
)。
所以,你的代码应该是:
ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
GZIPOutputStream zipStream = new GZIPOutputStream(byteStream);
zipStream.write(body.getBytes(this.charset));
zipStream.close();
byteBody = byteStream.toByteArray();