Internet Explorer 8 + Deflate

5

我有一个非常奇怪的问题...我真的希望有人能回答,因为我不知道在哪里寻求帮助。

我正在用C++编写一个cgi应用程序,由Apache执行并输出HTML代码。由于我的Web主机不支持mod_deflate,所以我从我的C++应用程序中自己压缩HTML输出。

我已经测试了Firefox 2、Firefox 3、Opera 9、Opera 10、Google Chrome、Safari、IE6、IE7、IE8,甚至是wget。它可以与任何浏览器一起使用,除了IE8。

IE8只显示“Internet Explorer无法显示网页”,没有任何信息。我知道这是因为压缩的原因,因为如果我禁用它,它就可以正常工作。

你知道我做错了什么吗?

我使用zlib进行压缩,精确的代码是:

    /* Compress it */
int compressed_output_size = content.length() + (content.length() * 0.2) + 16;
char *compressed_output = (char *)Alloc(compressed_output_size);
int compressed_output_length;
Compress(compressed_output, compressed_output_size, (void *)content.c_str(), content.length(), &compressed_output_length);

/* Send the compressed header */
cout << "Content-Encoding: deflate\r\n";
cout << boost::format("Content-Length: %d\r\n") % compressed_output_length;
cgiHeaderContentType("text/html");
cout.write(compressed_output, compressed_output_length);


static void Compress(void *to, size_t to_size, void *from, size_t from_size, int *final_size)
{
int ret;
z_stream stream;

stream.zalloc = Z_NULL;
stream.zfree = Z_NULL;
stream.opaque = Z_NULL;

if ((ret = deflateInit(&stream, CompressionSpeed)) != Z_OK)
    COMPRESSION_ERROR("deflateInit() failed: %d", ret);

stream.next_out = (Bytef *)to;
stream.avail_out = (uInt)to_size;
stream.next_in = (Bytef *)from;
stream.avail_in = (uInt)from_size;

if ((ret = deflate(&stream, Z_NO_FLUSH)) != Z_OK)
    COMPRESSION_ERROR("deflate() failed: %d", ret);

if (stream.avail_in != 0)
    COMPRESSION_ERROR("stream.avail_in is not 0 (it's %d)", stream.avail_in);

if ((ret = deflate(&stream, Z_FINISH)) != Z_STREAM_END)
    COMPRESSION_ERROR("deflate() failed: %d", ret);

if ((ret = deflateEnd(&stream)) != Z_OK)
    COMPRESSION_ERROR("deflateEnd() failed: %d", ret);

if (final_size)
    *final_size = stream.total_out;
return;
}

1
经过多次尝试,如果我将内容编码设置为gzip(实际上是deflate),它只能在Internet Explorer上运行,包括ie8,而在任何其他浏览器上都无法运行。如果我发送正确的deflate,则可以在任何浏览器上运行,包括ie6和ie7,但不能在ie8上运行。 - Andreas Bonini
cout << boost::format("Content-Encoding: %s\r\n") % ((UserAgent.GetBrowser() == INTERNET_EXPLORER && UserAgent.GetVersion() >= 8) ? "gzip" : "deflate"); // 这很好,但我仍然在寻找一个真正的答案,如果有人能想出来的话。 - Andreas Bonini
1
IE8的Accept-Encoding头部有什么线索吗? - John Kugelman
它发送deflate和gzip作为Accept-Encoding。在发送任何压缩输出之前,我会检查它是否包含“deflate”。 - Andreas Bonini
另外,请确保您已经阅读了这个SO问题https://dev59.com/zXRC5IYBdhLWcg3wK9yV。最好坚持使用gzip。 - esengineer
显示剩余2条评论
2个回答

6

gzip和deflate方法并不相同...它们非常接近,但是在头部有一些微妙的差异,所以如果您更改了内容编码,您也应该更改编码方法的参数(特别是窗口大小)!

参见:http://apcmag.com/improve_your_site_with_http_compression.htm

可能其他浏览器会忽略您的内容编码规范,并进行一些自动识别,但IE8不会...

参见:http://www.zlib.net/manual.html#deflateInit2

尝试使用:

method=Z_DEFLATED
windowBits=-15  (negative so that the header is suppressed)

并使用 "gzip" 作为内容编码


2
哇,谢谢!我爱你:D 不过需要稍作更正。有3种(!)压缩格式:zlib - 我一直在使用的那个,我以为它是“deflate”-,deflate和gzip。如果这还不够混乱,所有这3种格式显然都是使用zlib库创建的。不指定windowBits(就像我一直在做的那样)会输出zlib格式,使用负值(就像你建议的那样)会输出DEFLATED格式(而不是gzip!)。我还不确定如何输出gzip格式(现在用deflate在所有浏览器上都可以工作了),但再次感谢! :) - Andreas Bonini

5

我想澄清一下我对这个问题的发现,因为我自己编写了一个压缩算法和HTTP服务器,但令我失望的是IE8也无法识别我的压缩内容:

HTTP RFC 可以在http://www.faqs.org/ftp/rfc/rfc2616.pdf 找到。第17页明确规定在HTTP头部使用RFC 1950和RFC 1951进行压缩。RFC 1950只是定义了头部和尾部字节,而压缩算法则在RFC 1951中定义。当我按照规范进行编程时,IE8会失败。

当我忽略RFC 1950, 只使用RFC 1951时,它就能通过。

因此,我认为IE8没有正确遵循RFC 2616 第17页的规定,而其他所有浏览器都足够友好,接受任何格式的压缩内容。


我刚刚遇到了一个客户的Web缓存代理,它强制使用deflate压缩算法,而且猜猜他们选择了哪个实现方式?很可能是错误的实现方式,可能是为了支持IE8。不幸的是,我们的Java客户端使用标准HTTP库,期望正确的deflate实现方式。我必须关闭我们客户端中的deflate支持,并强制他们使用gzip或什么都不用。 - Marcus Adams
@MarcusAdams 在zlib中尝试使用inflateInit2(&strm, -MAX_WBITS)代替inflateInit(&strm) - user26742873

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接