json 将boost::beast::multibuffer转换为std::istream

fnatzsnv  于 2023-06-25  发布在  其他
关注(0)|答案(1)|浏览(145)

我正在从http::response<http::dynamic_body>::body()方法获取boost::beast::multibuffer对象。然后,我想像这样解析json内容:

boost::property_tree::read_json(requestBodyStream, propertyTree);

我应该使用boost::beast::buffers_to_stringstd::stringstream来获取requestBodyStream,还是可以不花费那么多内存复制缓冲区的内容?

gj3fmq9x

gj3fmq9x1#

一般来说,不要为 * 特定实现 * 编程,而要为 * 概念 * 编程。这里,dynamic_bodydocuments
这个主体使用DynamicBuffer作为基于内存的容器来保存消息有效载荷。使用此主体类型的消息可以被序列化和解析。
你不需要这个概念,因为你会完全在内存中使用它,但如果你这样做,你会像这样做:

net::streambuf sb;
sb.commit(net::buffer_copy(sb.prepare(body.size()), body.cdata()));

std::istream is(&sb);
ptree doc;
read_json(is, doc);

看到它**Live On Coliru**

#include <boost/asio.hpp>
#include <boost/asio/posix/stream_descriptor.hpp>

#include <boost/beast/http.hpp>
#include <boost/property_tree/json_parser.hpp>
#include <iostream>
namespace net = boost::beast::net;
namespace http = boost::beast::http;
using boost::property_tree::ptree;

int main() {
    net::posix::stream_descriptor input(net::system_executor{}, 0); // stdin

    http::response<http::dynamic_body> res;
    {
        net::streambuf readbuf;
        http::read(input, readbuf, res);
    }

    auto& body = res.body();

    net::streambuf sb;
    sb.commit(net::buffer_copy(sb.prepare(body.size()), body.cdata()));

    std::istream is(&sb);
    ptree doc;
    read_json(is, doc);

    write_json(std::cout << "Parsed body: ", doc);
}

它从stdin读取一个示例响应,让我们使用

HTTP/1.1 200 OK
Content-Length: 50

{"this":{"is":[1,2,3], "a":"sample"}, "object":42}

就像这样:

g++ -std=c++20 -O2 -Wall -pedantic -pthread main.cpp && ./a.out <<< $'HTTP/1.1 200 OK\r\nContent-Length: 50\r\n\r\n{\"this\":{\"is\":[1,2,3], \"a\":\"sample\"}, \"object\":42}'

指纹

Parsed body: {
    "this": {
        "is": [
            "1",
            "2",
            "3"
        ],
        "a": "sample"
    },
    "object": "42"
}

然而

现在我们已经回答了这个问题,让我们添加上下文:

  • 不要使用Boost属性树(除非您需要属性树)。提示:你不这样做)。看看输出:属性树不是JSON库
  • 除非你需要,否则不要使用动态体。在本例中,您读取内存中的整个消息,将其复制到内存中(转换为streambuf),使用本地化感知的istream(慢)从中读取,结果作为内存中的另一个副本存在。

相反,使用最简单的模型并使用JSON库,比如Boost.JSON

#include <boost/asio.hpp>
#include <boost/asio/posix/stream_descriptor.hpp>

#include <boost/beast/http.hpp>
#include <boost/json/src.hpp> // for header-only
#include <iostream>
namespace net  = boost::beast::net;
namespace http = boost::beast::http;
namespace json = boost::json;

int main() {
    net::posix::stream_descriptor input(net::system_executor{}, 0); // stdin

    http::response<http::string_body> res;
    {
        net::streambuf readbuf;
        http::read(input, readbuf, res);
    }

    auto doc = json::parse(res.body());
    std::cout << "Parsed body: " << doc << "\n";
}

它代码更少,效率更高,最重要的是,正确处理JSON!

相关问题