将`boost::beast::multibuffer`转换为`std::istream`。

huangapple go评论80阅读模式
英文:

Convert boost::beast::multibuffer to std::istream

问题

I want to parse json content from it like this:

我想这样解析JSON内容:

英文:

I am getting boost::beast::multibuffer object from http::response<http::dynamic_body>::body() method. Then, I want to parse json content from it like this:

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

Should I use boost::beast::buffers_to_string and std::stringstream to get requestBodyStream or is it possible to do without spending so much memory on copying the contents of the buffer?

答案1

得分: 1

总的来说,不要编写_具体实现_的程序,而要根据_概念_编写程序。在这里,dynamic_body 文档

> 这个主体使用DynamicBuffer作为保存消息有效载荷的基于内存的容器。使用这种主体类型的消息可以进行序列化和解析。

您不需要这个概念,因为您将完全在内存中使用它,但如果需要的话,可以像这样操作:

  1. net::streambuf sb;
  2. sb.commit(net::buffer_copy(sb.prepare(body.size()), body.cdata()));
  3. std::istream is(&sb);
  4. ptree doc;
  5. read_json(is, doc);

Coliru 上查看实际示例

  1. #include <boost/asio.hpp>
  2. #include <boost/asio/posix/stream_descriptor.hpp>
  3. #include <boost/beast/http.hpp>
  4. #include <boost/property_tree/json_parser.hpp>
  5. #include <iostream>
  6. namespace net = boost::beast::net;
  7. namespace http = boost::beast::http;
  8. using boost::property_tree::ptree;
  9. int main() {
  10. net::posix::stream_descriptor input(net::system_executor{}, 0); // stdin
  11. http::response<http::dynamic_body> res;
  12. {
  13. net::streambuf readbuf;
  14. http::read(input, readbuf, res);
  15. }
  16. auto& body = res.body();
  17. net::streambuf sb;
  18. sb.commit(net::buffer_copy(sb.prepare(body.size()), body.cdata()));
  19. std::istream is(&sb);
  20. ptree doc;
  21. read_json(is, doc);
  22. write_json(std::cout << "Parsed body: ", doc);
  23. }

这段代码从标准输入读取示例响应,例如:

  1. HTTP/1.1 200 OK
  2. Content-Length: 50
  3. {"this":{"is":[1,2,3], "a":"sample"}, "object":42}

然后输出:

  1. Parsed body: {
  2. "this": {
  3. "is": [
  4. "1",
  5. "2",
  6. "3"
  7. ],
  8. "a": "sample"
  9. },
  10. "object": "42"
  11. }

但是

既然我们已经回答了问题,让我们添加一些背景信息:

  • 不要使用 Boost Property Tree(除非你需要 Property Trees。提示:你不需要)。看看输出:Property Tree 不是一个 JSON 库。

  • 除非需要,不要使用 dynamic body。在这种情况下,您正在将整个消息读入内存,将其在内存中复制(以转换为 streambuf),使用区域感知 istream 从中读取(较慢),并将结果作为另一个副本存储在内存中。

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

Coliru 上查看实际示例

  1. #include <boost/asio.hpp>
  2. #include <boost/asio/posix/stream_descriptor.hpp>
  3. #include <boost/beast/http.hpp>
  4. #include <boost/json/src.hpp> // for header-only
  5. #include <iostream>
  6. namespace net = boost::beast::net;
  7. namespace http = boost::beast::http;
  8. namespace json = boost::json;
  9. int main() {
  10. net::posix::stream_descriptor input(net::system_executor{}, 0); // stdin
  11. http::response<http::string_body> res;
  12. {
  13. net::streambuf readbuf;
  14. http::read(input, readbuf, res);
  15. }
  16. auto doc = json::parse(res.body());
  17. std::cout << "Parsed body: " << doc << "\n";
  18. }

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

英文:

In general, don't program the specific implementation, but program to the concept. Here, dynamic_body documents:

> This body uses a DynamicBuffer as a memory-based container for holding message payloads. Messages using this body type may be serialized and parsed.

You don't need that concept, as you will be consuming this entirely in-memory anyways, but if you did, you would go about it like:

  1. net::streambuf sb;
  2. sb.commit(net::buffer_copy(sb.prepare(body.size()), body.cdata()));
  3. std::istream is(&sb);
  4. ptree doc;
  5. read_json(is, doc);

See it Live On Coliru

  1. #include <boost/asio.hpp>
  2. #include <boost/asio/posix/stream_descriptor.hpp>
  3. #include <boost/beast/http.hpp>
  4. #include <boost/property_tree/json_parser.hpp>
  5. #include <iostream>
  6. namespace net = boost::beast::net;
  7. namespace http = boost::beast::http;
  8. using boost::property_tree::ptree;
  9. int main() {
  10. net::posix::stream_descriptor input(net::system_executor{}, 0); // stdin
  11. http::response<http::dynamic_body> res;
  12. {
  13. net::streambuf readbuf;
  14. http::read(input, readbuf, res);
  15. }
  16. auto& body = res.body();
  17. net::streambuf sb;
  18. sb.commit(net::buffer_copy(sb.prepare(body.size()), body.cdata()));
  19. std::istream is(&sb);
  20. ptree doc;
  21. read_json(is, doc);
  22. write_json(std::cout << "Parsed body: ", doc);
  23. }

It reads a sample response from stdin, let's use

  1. HTTP/1.1 200 OK
  2. Content-Length: 50
  3. {"this":{"is":[1,2,3], "a":"sample"}, "object":42}

Like so:

  1. 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}'

Prints

  1. Parsed body: {
  2. "this": {
  3. "is": [
  4. "1",
  5. "2",
  6. "3"
  7. ],
  8. "a": "sample"
  9. },
  10. "object": "42"
  11. }

HOWEVER

Now that we've answered the question, let's add context:

  • Don't use Boost Property Tree (unless you need Property Trees. Hint: you do not). Look at the output: Property Tree is NOT a JSON library

  • Don't use dynamic body unless you need it. In this case you're reading the entire message in memory, copying it in memory (to convert to a streambuf), reading from it using locale-aware istream (slow) and the result lives as another copy in memory.

Instead, use the simplest model you can and use a JSON library, like, you know, Boost.JSON:

Live On Coliru

  1. #include <boost/asio.hpp>
  2. #include <boost/asio/posix/stream_descriptor.hpp>
  3. #include <boost/beast/http.hpp>
  4. #include <boost/json/src.hpp> // for header-only
  5. #include <iostream>
  6. namespace net = boost::beast::net;
  7. namespace http = boost::beast::http;
  8. namespace json = boost::json;
  9. int main() {
  10. net::posix::stream_descriptor input(net::system_executor{}, 0); // stdin
  11. http::response<http::string_body> res;
  12. {
  13. net::streambuf readbuf;
  14. http::read(input, readbuf, res);
  15. }
  16. auto doc = json::parse(res.body());
  17. std::cout << "Parsed body: " << doc << "\n";
  18. }

It's less code, more efficient and most importantly, correct handling of the JSON!

huangapple
  • 本文由 发表于 2023年6月13日 02:54:35
  • 转载请务必保留本文链接:https://go.coder-hub.com/76459521.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定