Boost.Asio实现HTTP服务器解析请求头后读取body阻塞问题求助
问题排查与修复方案
核心问题点
read_left_over方法使用input_stream >> extra_data读取streambuf剩余数据存在逻辑错误:>>流操作符默认跳过前导空白符,且遇到空白符就终止读取,会丢失body开头的有效数据,同时无法读全streambuf中已有的全部body数据。如果完整body已经随请求头一起被async_read_until读到本地缓存,计算得到的剩余待读bytes值大于0但客户端已经无数据可发,调用async_read_some就会永久等待。read_body方法中通过lambda捕获req的左值引用,如果req是栈上临时变量,回调触发时会出现引用悬空,引发未定义行为。async_read_some的回调未处理ec错误码,如果发生连接断开、读错误等异常,回调直接无响应,表象就是程序卡住。- 未确认
io_context运行状态:如果io_context已经停止运行,或者运行io_context的线程被阻塞,异步回调永远不会被调度执行。
修复方案
- 替换
read_left_over的读取逻辑,直接读取streambuf中所有可用数据,不要使用>>操作符:
void Connection::read_left_over(std::string &req, size_t &bytes) { size_t avail = input_stream.available(); if (avail > 0) { std::string extra_data(avail, '\0'); input_stream.read(&extra_data[0], avail); size_t read_len = std::min(avail, bytes); req.append(extra_data.data(), read_len); bytes -= read_len; } }
- 调用
internal_read_body之前先判断剩余bytes是否为0,如果已经读完直接调用回调,不需要发起异步读。 - 在
async_read_some的回调开头增加错误码处理逻辑:
if (ec) { error::print(ec); return; }
- 确认
io_context全程处于运行状态,没有被stop调用终止,也没有被其他阻塞逻辑占满运行线程。
调试方法
- 打印
read_left_over执行后剩余的bytes值、extra_data的长度与内容,确认是否已经读完全部body。 - 用tcpdump/wireshark抓包确认客户端是否发送了完整的、长度与
Content-Length匹配的body数据。
内容的提问来源于stack exchange,提问作者Bad_Panda
相关产品推荐
相关产品推荐

