Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/redis/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java GZIPOutputStream未正确压缩HTTP响应的字符串_Java_Gzip_Httprequest_Data Compression_Gzipoutputstream - Fatal编程技术网

Java GZIPOutputStream未正确压缩HTTP响应的字符串

Java GZIPOutputStream未正确压缩HTTP响应的字符串,java,gzip,httprequest,data-compression,gzipoutputstream,Java,Gzip,Httprequest,Data Compression,Gzipoutputstream,我正在编写一个简单的JavaHTTP服务器,它用JSON数据进行响应。我试图在发送数据之前对其进行GZip处理,但它通常会发送回GZip处理的数据,从而在浏览器中产生错误。例如,在Firefox中,它说: 内容编码错误 无法显示您试图查看的页面,因为它使用了无效或不受支持的压缩形式 有时,如果我压缩的字符串很小,没有特定的字符,它会工作,但如果有括号等,它似乎会出错。特别是,下面的示例文本失败 这是某种字符编码问题吗?我试过各种各样的方法,但都不想轻易奏效 String text;

我正在编写一个简单的JavaHTTP服务器,它用JSON数据进行响应。我试图在发送数据之前对其进行GZip处理,但它通常会发送回GZip处理的数据,从而在浏览器中产生错误。例如,在Firefox中,它说:

内容编码错误 无法显示您试图查看的页面,因为它使用了无效或不受支持的压缩形式

有时,如果我压缩的字符串很小,没有特定的字符,它会工作,但如果有括号等,它似乎会出错。特别是,下面的示例文本失败

这是某种字符编码问题吗?我试过各种各样的方法,但都不想轻易奏效

String text;            
private Socket server;
DataInputStream in = new DataInputStream(server.getInputStream());
PrintStream out = new PrintStream(server.getOutputStream());

while ((text = in.readLine()) != null) {
    // ... process header info
    if (text.length() == 0) break;
}

out.println("HTTP/1.1 200 OK");
out.println("Content-Encoding: gzip");
out.println("Content-Type: text/html");
out.println("Connection: close");


// x is the text to compress
String x = "jsonp1330xxxxx462022184([[";
ByteArrayOutputStream outZip = new ByteArrayOutputStream();
GZIPOutputStream gzip = new GZIPOutputStream(outZip);

byte[] b = x.getBytes(); // Changing character encodings here makes no difference

gzip.write(b);
gzip.finish();
gzip.close();
outZip.close();
out.println();
out.print(outZip);
server.close();

更新:这不再是正确答案,请参见上面@amichair的答案

与直觉相反,我认为GZIPOutputStream不适合流媒体。试试这个:

...
out.println("Content-Encoding: deflate");  // NOTICE deflate encoding
out.println("Content-Type: text/html");
out.println("Connection: close");
out.println();
String x = "jsonp1330xxxxx462022184([[";
DeflaterInputStream dis = new DeflaterInputStream(out);
dis.write(x.getBytes("utf-8"));   // JSON is UTF-8
dis.close();
server.close(); //  this a bad idea, the client may not have read the data yet

公认的答案是错误的

GZIPOutputStream
确实可以用于在HTTP中实现
gzip
内容编码。事实上,这正是我在轻量级HTTP服务器中实现它的方式。对
deflate
内容编码的支持是相同的,只是使用了
DeflaterOutputStream
。上面代码的问题只是它有bug:-)

  • 所有
    println
    语句(包括底部的语句)应替换为
    print
    ,并在字符串末尾显式添加
    \r\n
    。这是因为
    println
    打印的换行符依赖于平台,因此,例如在Linux上,它只打印
    \n
    ,而HTTP需要完整的CRLF(
    \r\n

  • out.print(outZip)
    基本上调用
    outZip.toString()
    并将其打印到流中。但是,
    outZip
    包含压缩的二进制数据,因此将其转换为字符串(使用任意平台默认编码,甚至更少)很可能损坏数据

  • 代码获取字符串,将其转换为字节,对其进行压缩,再将其转换回字符串,再将其转换回字节并写出。相反,它只需要将字符串转换为字节,压缩并写出它们。您也不需要使用
    ByteArrayOutputStream
    ,因此
    GZIPOutputStream
    可以直接包装底层输出流。只是别忘了在页眉(和尾随的CRLF)之后刷新打印流,然后才从正文的压缩流开始

  • 关闭资源应该在finally或try with resources块中完成,并且具有正确的顺序和时间

  • 在此示例中,连接在流的末尾关闭,这很好。但一般来说,如果您想保持连接的活动性并流式传输长度未知的潜在大数据(您事先不知道压缩的大小),那么还需要实现
    分块的
    传输编码(这非常简单)

在代码固定的情况下,
GZIPOutputStream
就像一个符咒


然而,尽管这对于教育目的来说很好,但请注意,这不是一个HTTP服务器,即使是固定的。您可以进一步阅读RFC2616或7230来了解HTTP还需要做什么。。。但是为什么要重新发明weel呢?有很多轻量级的可嵌入HTTP服务器,您可以使用它们来轻松完成工作。

Jusr好奇,您使用的是哪台服务器?因为这样的设置在服务器级别更容易完成。例如:对于tomcat,您必须为内容类型
application/json
启用
gzip
压缩,就完成了。或者,正如第一句话所说,你实际上是在自己编写服务器?在最后一个响应标题行之后,在内容之前,你至少缺少了一个
CRLF
。感谢各位的评论-我实际上是在编写自己的服务器,因为这真的只是一个简单的任务。我打开一个端口,只监听来自Javascript JSONP请求的请求。我希望这不会对安全造成任何影响。关于CRLF,我相信我在底部有:out.println();看看这个答案,谢谢!我不得不将DeflaterInputStream更改为DeflaterOutputStream,但这非常有效!在关闭服务器连接之前,我应该等待什么?它似乎是这样工作的,但正如您所说,我不希望过早地发生随机丢弃。实际上,如果您在关闭套接字之前刷新()输出流(在您的示例中为“out”),这可能没什么问题。如果您对此答案感到满意,请将其标记为正确答案。这是正确答案。当我在下面写下我的原始答案时,仍然有一些浏览器(我正在看IE6)不支持gzip编码(但支持deflate)。