网上搜来的关键几句话:
gzip与deflate区别
deflate使用inflateInit(),而gzip使用inflateInit2()进行初始化,比 inflateInit()多一个参数: -MAX_WBITS,表示处理raw deflate数据。因为gzip数据中的zlib压缩数据块没有zlib header的两个字节。使用inflateInit2时要求zlib库忽略zlib header。在zlib手册中要求windowBits为8..15,但是实际上其它范围的数据有特殊作用,见zlib.h中的注释,如负数表示raw deflate。
Apache的deflate变种可能也没有zlib header,需要添加假头后处理。即MS的错误deflate (raw deflate).zlib头第1字节一般是0x78, 第2字节与第一字节合起来的双字节应能被31整除,详见rfc1950。例如Firefox的zlib假头为0x7801,python zlib.compress()结果头部为0x789c。
=========
好了,使用ZlibEx中的ZCompressStr进行压缩后发现头两个字节是0x7801,这个跟Firefox的zlib假头一毛一样。既然知道了假头是两个字节,剩下的事情就很简单了,把这两个字节直接删掉,然后告诉Indy我们发送的是deflate数据,再把数据流长度发过去后直接发送数据流,剩下的事情就交给浏览器去干了。关键代码像这样:
sDest := ZCompressStr(sSrc); Result := Length(sDest) - 2; //删除两个字节的头 if Result > 0 then AResponseInfo.ContentStream.Write(sDest[1 + 2], Result); ...... //发送的数据格式和数据长度 AResponseInfo.ContentEncoding := 'deflate'; AResponseInfo.ContentLength := Result; AResponseInfo.WriteHeader; //发送数据内容 AResponseInfo.ContentStream.Position := 0; AResponseInfo.WriteContent;
结果很漂亮,无论是IE还是Chrome都能很好的理解页面内容。
这可能是为数不多的原生程序用起来很爽的原因了:只要理解原理剩下的事情都是几行代码就能轻松解决的。另外,知道了压缩原理自然在解压时判断一下头两个字节然后根据需要加上两个字节的内容就可以从容进行解压了,代码就不写了。
顺便说说一些网页搜到的乱七八糟的误导(错误)内容:
1.gzip比deflate压缩比高但性能稍差。核心都是deflate算法,只是压缩比的选择不同而已。在相同压缩比下,除了gzip比无deflate头(两字节)多了18个字节(具体内容请参考相关文档)以外,没发现有任何区别(要是有区别的话问题就大了)。所以这种说法纯粹是胡说八道。
2.什么deflate是过时的压缩格式不建议使用等等内容。还是上面那句话,除了十几个字节的额外数据外,完全没发现有任何区别(还是那句话:有区别的话问题就大了),所以,这种说法同样是胡说八道。
真要吐槽的话,只能说:小白太多,胡说八道成本太低。