3

2019/08/14:这篇文章已经过时了。Webcc 已经演化成了一个比较完备的纯 HTTP 程序库。
详见:Webcc: 轻量级 C++ HTTP 程序库

Webcc 是我自己写的一个 C++ Web Service 程序库,网络通信基于 Boost Asio,跨平台,轻量、高效。它并非只是一个玩具,目前正应用于我们实际的项目,而且还在不断更新和完善。

Webcc 同时支持客户端和服务端,你可以用它调用已经存在的 Web Service,也可以用它实现自己的 Web Service,且同时支持 REST 和 SOAP 两种方式。

考虑到用 SOAP 的人越来越少,webcc 对 SOAP 的支持可以通过宏 WEBCC_ENABLE_SOAP 在编译时完全剔除掉。

Webcc 内部对 SOAP 消息的包装和解析依赖于 PugiXml。如果禁掉 SOAP,PugiXml 自然也会一并禁掉;如果启用 SOAP,希望你能承担对 PugiXml 的这一份小小依赖。

对 SOAP 部分的介绍就这么多,具体可见去年的这篇文章:C++ 调用 SOAP Web Service

REST Server

假定你要提供一个关于图书的 REST Server,提供下面这些操作或接口:

  • 查询图书(基于某些特定的条件);
  • 添加一本新图书;
  • 获取一本图书的详细信息;
  • 更新一本图书的信息;
  • 删除一本图书。

前面两个操作可以通过继承 webcc::RestListService 来实现:

class BookListService : public webcc::RestListService {
 protected:
  // 查询图书(基于某些特定的条件)
  // GET /books?<query>
  bool Get(const webcc::UrlQuery& query,
           std::string* response_content) override;

  // 添加一本新图书
  // POST /books
  // |request_content| 包含了新图书的数据,为 JSON 格式的字符串
  bool Post(const std::string& request_content,
            std::string* response_content) override;
};

其他几个操作,则需要继承自 webcc::RestDetailService

class BookDetailService : public webcc::RestDetailService {
 protected:
  // 获取一本图书的详细信息
  bool Get(const std::vector<std::string>& url_sub_matches,
           const webcc::UrlQuery& query,
           std::string* response_content) override;

  // 更新一本图书的信息
  bool Put(const std::vector<std::string>& url_sub_matches,
           const std::string& request_content,
           std::string* response_content) override;

  // 删除一本图书
  bool Delete(const std::vector<std::string>& url_sub_matches) override;
};

在 Python 的 Django 框架中,有几种不同的视图(View),其中 XxxListView 对应于一列对象,而 XxxDetailView 对应于单个对象。Webcc 的 RestListServiceRestDetailService 就是参考了 Django 的这一设计。

对于 RestListService,URL 一般为复数形式,比如 /books。对于 GET 请求,就是查询对象,URL 一般会带 query,比如 /books?author=Barnes;对于 POST 请求,就是创建新对象,信息由 HTTP 请求体携带,一般为 JSON 格式。

对于 RestDetailService,URL 一般为单数,比如 /book,然后还要指定对象的 ID,最终的 URL 格式为 /book/{BookID},这个 ID 最终可以通过 url_sub_matches 这个参数拿到。RestDetailService 支持 GET、PUT、PATCH 和 DELETE 几种请求,分别对应于获取、更新、部分更新和删除。

下面看一下 BookDetailService::Get() 的实现:

bool BookDetailService::Get(const std::vector<std::string>& url_sub_matches,
                            const webcc::UrlQuery& query,
                            std::string* response_content) {
  if (url_sub_matches.size() != 1) {
    return false;
  }
  const std::string& book_id = url_sub_matches[0];

  // 接下来:
  // - 通过 book_id 从数据库拿到这个图书,
  // - 然后把图书信息转换成 JSON 格式的字符串,
  // - 最后把 JSON 字符串赋值给输出参数 response_content。
}

Service 自己并不能运行,需要把它们绑定到 RestServer,下面是 main() 里的部分代码:

webcc::RestServer server(8080, 2);

server.Bind(std::make_shared<BookListService>(), "/books", false);
server.Bind(std::make_shared<BookDetailService>(), "/book/(\\d+)", true);

server.Run();

先创建一个 RestServer 对象,端口号为 8080,后台的工作线程数为 2
然后分别创建 BookListServiceBookDetailService,都用 std::shared_ptr 来自动管理对象生命期。
最后绑定 services 到特定的 URL,其中 BookDetailService 的 URL 是一个正则表达式,(\\d+) 最后匹配下来的部分就存在参数 url_sub_matches 中。


adam1q84
1.7k 声望244 粉丝

GitHub 首页:[链接]