如何解码gzip编码的HTML?

3

我从网站服务器获取了数据:

data := '
HTTP/1.1 200 OK
Content-Encoding: gzip
Vary: Accept-Encoding
Content-type: text/html
Transfer-Encoding: chunked
Server: Apache

3d5
????????????????????????????????????
????????????????????????????????????
????????????????????????????????????
';

数据大小为:3d5(十六进制) 所有数据都存储到TIdBytes变量"data"中。

如何解码gzip数据,对其进行更改,并重新编码并编辑长度3d5为新长度。

2个回答

7
Transfer-Encoding 响应头设置为 chunked。这意味着服务器将以块的形式发送数据,每个块都指示其自身的大小,其中长度为 0 的块表示数据的结束。 3d5 是第一个块的大小。如果响应中只有一个数据块,则它将是 HTML 的完整大小。 TIdHTTP 内部会处理块数据。如果去块后的数据已经被 gzip 压缩,你可以在向 TIdHTTP.Compressor 属性分配 TIdCompressorZLib 等继承自 TIdZLibCompressorBase 的组件之前,让 TIdHTTP 为你解压缩数据。

那么我认为在获得所有块之前是无法解码块的吧? - jmp
2
如果HTTP数据存储在内存中,例如StringTIdBytes,您可以使用TIdHTTP对其进行解码。将TIdIOHandlerStream组件分配到TIdHTTP.IOHandler属性,并为IOHandler提供一个从内存读取的TStream(您可以使用Indy的TIdMemoryBufferStream类),以及一个空TStream用于写入。然后,使用伪造的URL调用TIdHTTP的任何请求方法,例如Get()。由TIdIOHandlerStream丢弃所生成的HTTP请求,并且TIdHTTP将按原样解析TStream数据。然后,您可以根据需要处理已解码的数据。 - Remy Lebeau
TIdIOHandlerStream有一个构造函数,带有AReceiveStreamASendStream参数,以及一个OnGetStreams事件,带有VReceiveStreamVSendStream参数。其中任何一个都可以用来将您的数据作为ReceiveStream提供给IOHandler,并将nil作为SendStream。对于ReceiveStream,请使用TIdMemoryBufferStreamTMemoryStreamTBytesStream或其他任何您想要用来保存HTTP数据的TStream类型。 - Remy Lebeau
发现为什么不工作了,忘记设置 my_stream.Position := 0;。 - jmp
是的,那就是做法。但是,你不需要调用 TStringString.Write()。相反,将你的 data 传递给 TStringStream 构造函数即可。 - Remy Lebeau
显示剩余2条评论

1
您可以使用ZlibExGz单元的GZDecompressStr()函数来解压HTTP Gzip正文。只需将数据作为参数传递,就像您从HTTP响应消息中获取的那样,它将返回解压缩的数据。
uses ZlibExGz;

var s:string;

begin
 // read the gzipped data in "s"
 s:=GZDecompressStr(s);
 // now "s" contains uncompressed data
end;

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