You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Boost异步读取HTTP分块响应体时编译错误求助

Boost Beast异步读取HTTP分块响应体编译错误解决

问题描述

尝试用Boost异步读取HTTP分块响应体,已成功读取响应头,但读取响应体时编译报错。最小示例代码如下:

void body_read_loop() {
    http::response_parser<http::buffer_body> parser_ = http::response_parser<http::buffer_body>();
    async_read(*sslSocket, buf, parser_, [this](error_code ec, size_t) {
    });
}

编译时抛出错误:

Call to deleted constructor of 'boost::beast::http::parser<false, boost::beast::http::buffer_body>'

疑惑点:调用的async_read函数明明是按引用传入parser,函数签名如下:

template<
    class AsyncReadStream,
    class DynamicBuffer,
    bool isRequest,
    BOOST_BEAST_ASYNC_TPARAM2 ReadHandler>
BOOST_BEAST_ASYNC_RESULT2(ReadHandler)
async_read(
    AsyncReadStream& stream,
    DynamicBuffer& buffer,
    basic_parser<isRequest>& parser,
    ReadHandler&& handler)
{

完整可复现代码(Ubuntu+Boost 1.74.0环境)

#include <boost/beast.hpp>
#include <iostream>
#include <span>
namespace net   = boost::asio;
namespace beast = boost::beast;
namespace http  = beast::http;
using boost::system::error_code;
using net::ip::tcp;

static void check(error_code& ec) {
    if (ec && ec != http::error::need_buffer) // expected
        throw boost::system::system_error(ec);
}

template <typename Derived> struct CommonImpl {
    net::io_context ioc;
    tcp::socket s{ioc};
    tcp::resolver r{ioc};
    http::request<http::empty_body> req{http::verb::get, "/stream-bytes/2000?seed=42", 11};

    void run() {
        r.async_resolve(
             "httpbin.org", "http",
            beast::bind_front_handler(&CommonImpl::on_resolved, this));

        ioc.run();
    }

    void on_resolved(error_code ec, tcp::resolver::results_type eps) {
        check(ec);

        async_connect(s, eps, [this](error_code ec, tcp::endpoint) {
            check(ec);
            req.set(http::field::host, "httpbin.org");
            async_write(s, req, beast::bind_front_handler(&CommonImpl::on_sent, this));
        });
    }

    void on_sent(error_code ec, size_t) {
        check(ec);
        static_cast<Derived&>(*this).do_read_response();
    }
};

struct BufferImpl : CommonImpl<BufferImpl> {
    http::response_parser<http::buffer_body> p;
    http::response<http::buffer_body>& res  = p.get();
    http::buffer_body::value_type& body_val = res.body();
    beast::flat_buffer buf;

    void do_read_response() {
        async_read_header(s, buf, p, beast::bind_front_handler(&BufferImpl::on_headers, this));
    }

    void on_headers(error_code ec, size_t) {
        check(ec);

        assert(p.is_header_done());
        std::cout << "\n---\nresponse headers: " << res.base() << std::endl;

        body_read_loop();
    }

    size_t checksum = 0;
    size_t n        = 0;
    std::array<uint8_t, 512> block;

    void body_read_loop() {
        if (!p.is_done()) {
            body_val.data = block.data();
            body_val.size = block.size();
            async_read(s, buf, p, [this](error_code ec, size_t) {
                check(ec);

                size_t decoded = block.size() - body_val.size;
                n += decoded;

                std::cout << "parsed " << decoded << " body bytes\n";

                for (auto b : std::span(block).first(decoded))
                    checksum ^= b;

                body_read_loop();
            });
        } else {
//            fmt::print("buffer body, {} bytes streaming decoded, chunked? {}\n", n, p.chunked());
//            fmt::print("buffer body checksum: {:#0x}\n", checksum);
        }
    }
};

int main(int argc, char **argv) {
    BufferImpl{}.run();
    return 0; 
}

错误原因及解决方法

编译错误的核心原因是**response_parser类禁止拷贝构造与拷贝赋值**,你最初的最小示例中parser_ = http::response_parser<http::buffer_body>();这行代码试图执行拷贝赋值操作,触发了被删除的拷贝构造函数。

你的完整MCVE代码其实已经规避了这个问题(成员变量p是直接初始化的),但仍需注意两个关键点:

  1. 确保response_parser对象的生命周期覆盖整个异步操作流程,不能在异步回调完成前被销毁
  2. 永远不要尝试拷贝或赋值response_parser实例,始终通过引用传递

针对最初的最小示例,修正方式为直接默认初始化parser,避免拷贝操作:

void body_read_loop() {
    http::response_parser<http::buffer_body> parser_; // 直接默认初始化
    async_read(*sslSocket, buf, parser_, [this](error_code ec, size_t) {
        // 处理逻辑
    });
}

另外,使用buffer_body处理分块响应时,每次调用async_read前都要设置好有效的缓冲区(如你在MCVE的body_read_loop中所做),确保读取操作有可用的内存空间。


内容的提问来源于stack exchange,提问作者Max

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 12:35:13