Win32 C++ Boost.Asio HTTP请求:在线服务器响应含冗余数据排查
你遇到的这个首尾冗余整数(比如示例里的26和0),十有八九是**HTTP分块传输编码(Chunked Transfer Encoding)**的块长度标识。本地服务器运行正常,是因为它可能没启用分块传输;而在线服务器用了HTTP/1.1的默认分块机制,你的代码又没处理这种响应格式,才会把块长度标记和JSON内容混在一起读出来。
问题根源拆解
HTTP/1.1协议默认支持分块传输,服务器返回的响应实际结构是这样的:
26\r\n {"success":-2,"message":"no username"}\r\n 0\r\n \r\n
你看到的26是当前数据块的字节长度(十六进制转十进制后的值),0则表示所有块传输结束,这些标记被你的代码当成了响应内容的一部分,才出现了冗余数据。
两种解决方案
方案1:强制服务器禁用分块传输
在请求头里添加Transfer-Encoding: identity,明确告诉服务器不要使用分块编码,改用Content-Length标识响应长度。修改后的请求代码如下:
std::ostream request_stream(&request_); request_stream << "POST " << path << " HTTP/1.1\r\n"; request_stream << "Host: " << server << "\r\n"; request_stream << "User-Agent: C/1.0\r\n"; request_stream << "Content-Type: application/x-www-form-urlencoded\r\n"; request_stream << "Content-Length: " << str.length() << "\r\n"; request_stream << "Accept: */*\r\n"; request_stream << "Transfer-Encoding: identity\r\n"; // 新增此行 request_stream << "Connection: close\r\n\r\n"; request_stream << str ;
另外,也可以直接把HTTP版本改为HTTP/1.0(HTTP/1.0本身不支持分块传输),不过这种方式会丢失HTTP/1.1的部分特性,优先推荐上面的请求头修改方案。
方案2:正确解析分块传输响应
如果服务器强制要求使用分块传输(比如部分API仅支持HTTP/1.1分块),你需要按照HTTP分块规则解析响应,步骤如下:
- 先读取响应头,直到遇到
\r\n\r\n分隔符; - 检查响应头是否包含
Transfer-Encoding: chunked; - 循环读取每个数据块:
- 读取一行块长度(十六进制格式),转成十进制;
- 如果长度为0,终止解析;
- 读取对应长度的字节数据,拼接成最终内容;
- 跳过块末尾的
\r\n分隔符。
以下是基于Boost.Asio的分块解析示例代码:
// 假设已完成响应头读取,开始处理分块内容 boost::asio::streambuf response; std::string json_content; while (true) { // 读取块长度行 std::string chunk_len_str; boost::asio::read_until(socket_, response, "\r\n"); std::istream resp_stream(&response); std::getline(resp_stream, chunk_len_str); // 移除行尾的\r字符 if (!chunk_len_str.empty() && chunk_len_str.back() == '\r') { chunk_len_str.pop_back(); } // 十六进制转十进制 std::size_t chunk_len = std::stoul(chunk_len_str, nullptr, 16); if (chunk_len == 0) break; // 读取当前块的内容 char chunk_buf[1024]; std::size_t bytes_read = boost::asio::read(socket_, response, boost::asio::transfer_exactly(chunk_len)); resp_stream.read(chunk_buf, bytes_read); json_content.append(chunk_buf, bytes_read); // 跳过块末尾的\r\n boost::asio::read_until(socket_, response, "\r\n"); } // 此时json_content即为纯JSON数据
额外注意点
要确认str.length()是否准确对应请求体的字节数:如果formData包含多字节字符(比如中文),std::string::length()返回的是字符数而非字节数,会导致Content-Length错误,引发服务器异常响应。这种情况建议改用str.size()(UTF-8字符串的size()表示字节数),或者明确计算字节数。
内容的提问来源于stack exchange,提问作者Bernie gach

