• C++构建response


    前言

    本文完整代码见仓库

    我正在写一个玩具程序。程序接收到一个request, 并进行解析。解析之后,它需要构造一个response进行发送。这其中有两个需求:

    • 构建一个response,并将转换成字符串,以便通过套接字发送。
    • response的body部分,是一个json结构转换的字符串,这样内容的结构比较灵活。

    boost提供了http::responseChapter 1. Boost.JSON。本文利用这两部分,实现上面的需求。

    注:boost在Version 1.75.0添加的JSON库。ubuntu20包管理器提供的是1.71版本,所以需要进行boost的源码安装,可参考cmake下切换使用不同版本的boost。(最开始,我懒得编译安装,去拉去了boostorg/json这一部分,但是它还依赖其他部分,单独不太行似乎。)


    构建Json

    Boost.JSON之前,boost已经有json解析工具,property_treeproperty_tree解析配置文件,还是挺顺手的。

    Boost.PropertyTree的介绍可以参考:C++ Boost JSON解析库的使用、《Boost完全开发指南》7.10 property_tree。

    但,既然boost后来专门为json提供了一个库,虽然不知道它为啥好,我们还是使用它吧。

    我们带着目标去看文档。假设,我们将构建下面的json结构,并转换成字符串,我们该如何去实现它呢?

    {
      "info":[
        {"name":"张三", "message":"你好世界"},
        {"name":"Bob", "message":"hello world"}
      ]
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    参考Document Model,boost::json提供了四种模型。

    • array: JSON 值的序列容器,支持动态大小和快速、随机访问。接口和性能特征与. std::vector
    • object: 具有唯一键的键值对的关联容器,其中键是字符串,映射类型是 JSON 值。搜索、插入和删除具有平均的持续时间复杂度。此外,元素连续存储在内存中,允许缓存友好的迭代。
    • string: 连续的字符范围。该库假定字符串的内容仅包含有效的 UTF-8。
    • value: 一种特殊的变体,可以保存六种标准 JSON 数据类型中的任何一种。(这种有点特殊,当上面三种搞不定的时候,可以考虑这个)

    一般构建json结构,是从最内层开始的。我们看下它的结构。

    • 最基础的,是字符串,我们可以用string。
    • 序号一,是个键值对,我们可以用object容器。
    • 序号二,是两个在同一层次的键值对,所以我们可以加入之前相同的object容器。
    • 序号三:是一个数组,我们可以使用arrar。
    • 最外面一层,是一个新的object, 它的值也是个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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    输出如下:

    {"info":[{"name":"张三","message":"你好世界"},{"name":"Bob","message":"hello world"}]}
    
    • 1

    构建response

    假定我们已经知道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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48

    输出如下:

    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"}]}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
  • 相关阅读:
    java计算机毕业设计家校沟通程序(附源码、数据库)
    开启可视化金融时代!菊风联合助推山东农信视频银行项目
    聚苯乙烯/聚4-乙烯基吡啶功能微球/CF3-PPFPA-PS聚苯胺/聚苯乙烯微球的制备
    第3章 处理机调度与死锁
    积分商城可设置的四种兑换商品类型
    设计模型之六大原则(有的地方称之为七大原则)
    JS判断数据类型
    博客园众包平台:游戏开发者找人长期合作建设自己的网站
    Deque初步了解
    adguarg通过dns代理全局过滤广告,全系统操作指南
  • 原文地址:https://blog.csdn.net/sinat_38816924/article/details/127798345