http响应体是gzip压缩的,直接用std::istream读取会导致乱码;需先检查响应头content-encoding是否为gzip,再用zlib等库解压原始字节流,最后转为字符串。

HTTP响应体是gzip压缩的,但std::istream直接读取会乱码
这是最常见现象:用libcurl或Boost.Beast拿到响应体后,std::string里全是不可见字节,std::cout 输出空或乱码。根本原因是HTTP头里有<code>Content-Encoding: gzip,但C++标准库不带解压能力,必须手动接入zlib。
用zlib的inflate函数解压内存中的gzip数据
别碰gzopen/gzread——它们只认文件路径,对HTTP流里的内存块无效。必须用底层inflate接口:
-
inflateInit2(&strm, 16 + MAX_WBITS):第二个参数16 + MAX_WBITS是关键,表示启用gzip头解析(仅加16不行,zlib默认只认zlib格式) - 输入缓冲区
strm.next_in要指向原始响应体字节数组,strm.avail_in设为长度 - 输出缓冲区需预分配足够空间(可先按1.5倍原始长度估算,解压失败时再扩容)
- 循环调用
inflate()直到返回Z_STREAM_END,中间遇到Z_BUF_ERROR说明输出缓冲不够,需扩大并重试
示例关键片段:
z_stream strm; strm.zalloc = Z_NULL; strm.zfree = Z_NULL; inflateInit2(&strm, 16 + MAX_WBITS); strm.next_in = const_cast<bytef>(data.data()); strm.avail_in = data.size(); // ... 分配outbuf,循环inflate() ...</bytef>
libcurl内置gzip支持能省事,但默认不开启
很多人不知道libcurl其实自带zlib绑定,只需两行代码就能让curl_easy_perform自动解压:
- 设置
CURLOPT_ENCODING为""(空字符串),它会自动在Accept-Encoding头里填gzip, deflate - 确保编译libcurl时启用了zlib(Linux发行版包通常已启用;Windows下若用vcpkg装的
curl,默认含zlib) - 注意:解压后
Content-Encoding头仍存在,但响应体已是明文,无需再调inflate
如果curl报错Unsupported encoding type,基本是zlib没链接上,不是代码问题。
用Boost.Beast处理gzip流时,别依赖http::async_read自动解压
Beast本身不处理编码,http::response_parser拿到的body()仍是原始gzip字节。常见错误是直接对parser.get().body()调std::string::c_str()去解析JSON——必然失败。
- 必须显式检查
parser.get().base().at("content-encoding") == "gzip" - 解压逻辑仍得自己写(同zlib inflate那段),不能指望Beast代劳
- 若用
http::buffer_body接收,记得parser.release()后用boost::beast::buffers_to_string转成std::string再喂给zlib,别直接传buffer_body::value_type
gzip头和尾部校验字段很严格,少一个字节、错一个标志位,inflate()就会返回Z_DATA_ERROR——这种错误不会抛异常,容易被忽略成“解压失败”,实际可能是HTTP截断或代理篡改了响应体。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











