本文完整代码见仓库。
我正在写一个玩具程序。程序接收到一个request, 并进行解析。解析之后,它需要构造一个response进行发送。这其中有两个需求:
boost提供了http::response和Chapter 1. Boost.JSON。本文利用这两部分,实现上面的需求。
注:boost在Version 1.75.0添加的JSON库。ubuntu20包管理器提供的是1.71版本,所以需要进行boost的源码安装,可参考cmake下切换使用不同版本的boost。(最开始,我懒得编译安装,去拉去了boostorg/json这一部分,但是它还依赖其他部分,单独不太行似乎。)
在Boost.JSON
之前,boost已经有json解析工具,property_tree。property_tree
解析配置文件,还是挺顺手的。
Boost.PropertyTree
的介绍可以参考:C++ Boost JSON解析库的使用、《Boost完全开发指南》7.10 property_tree。
但,既然boost后来专门为json提供了一个库,虽然不知道它为啥好,我们还是使用它吧。
我们带着目标去看文档。假设,我们将构建下面的json结构,并转换成字符串,我们该如何去实现它呢?
{
"info":[
{"name":"张三", "message":"你好世界"},
{"name":"Bob", "message":"hello world"}
]
}
参考Document Model,boost::json提供了四种模型。
一般构建json结构,是从最内层开始的。我们看下它的结构。
分析清楚结构,参考Quick Look,照葫芦画瓢编码即可。
#include
#include
#include
#include
#include
using namespace std;
int main(int argc, char** argv)
{
vector<pair<string, string>> info;
info.push_back(make_pair("张三","你好世界"));
info.push_back(make_pair("Bob", "hello world"));
boost::json::array info_array;
for(auto &in : info) {
boost::json::object obj;
obj["name"] = in.first;
obj["message"] = in.second;
info_array.emplace_back(obj);
}
boost::json::object info_json;
info_json.emplace("info", info_array);
string info_json_str = boost::json::serialize(info_json);
cout << info_json_str << endl;
}
输出如下:
{"info":[{"name":"张三","message":"你好世界"},{"name":"Bob","message":"hello world"}]}
假定我们已经知道response的基本结构。我之前整理过:http消息简介、http-parse的C++封装。
如果之前没有看过boost的response的构造,这部分编码会有点难。因为照葫芦画瓢,但是没有个好的葫芦。即,boost的这部分文档写的不好,网上也没有好的参考代码。略微好点的示例代码是http_examples.hpp。
下面是个示例代码,抛砖引玉的去看看里面的源码,便能比较清楚了。
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
std::string json_body() {
vector<pair<string, string>> info;
info.push_back(make_pair("张三","你好世界"));
info.push_back(make_pair("Bob", "hello world"));
boost::json::array info_array;
for(auto &in : info) {
boost::json::object obj;
obj["name"] = in.first;
obj["message"] = in.second;
info_array.emplace_back(obj);
}
boost::json::object info_json;
info_json.emplace("info", info_array);
string info_json_str = boost::json::serialize(info_json);
return info_json_str;
}
int main(int argc, char** argv)
{
namespace http = boost::beast::http;
http::response<http::string_body> resp;
resp.set(http::field::server, "tiny-server"); // 处理请求的软件
resp.set(http::field::access_control_allow_origin, "*"); // 允许跨与访问
resp.set(http::field::content_type, "application/json;charset=utf8"); // 返回的内容类型
resp.body() = json_body(); // body内容
resp.prepare_payload(); // 根据body的长度,调整Content-Length
resp.result(http::status::ok); // 响应值为200
// 将response转换成字符串
// https://stackoverflow.com/questions/71514303/how-to-convert-httpresponsehttpstring-bodybase-to-stdstring
// https://github.com/boostorg/beast/issues/819
const std::string str_headers = boost::lexical_cast<std::string>(resp.base());
std::string str_body = resp.body().data();
std::cout << str_headers << str_body;
}
输出如下:
HTTP/1.1 200 OK
Server: tiny-server
Access-Control-Allow-Origin: *
Content-Type: application/json;charset=utf8
Content-Length: 92
{"info":[{"name":"张三","message":"你好世界"},{"name":"Bob","message":"hello world"}]}