一個(gè)輕量級(jí)、高性能的 C++ Web 框架
說(shuō)起 Web 開(kāi)發(fā),大多數(shù)人會(huì)想到 Java、Python、Golang ... 因?yàn)樗鼈兊闹髁?Web 框架有很多,Java 有非常知名的 Spring 全家桶,Python 有大而全的 Django、小而精的 Flask、高性能的 Tornado,Golang 也有快速靈活的 Gin、Echo 等框架。
相比之下,C/C++ 陣營(yíng)則遜色不少。之前,我曾寫(xiě)過(guò)一篇《C++ Web(HTTP)開(kāi)發(fā) 10 大利器》,其中介紹了一些 C/C++ Web 框架。有一個(gè)名為 Oat++ 的很不錯(cuò),輕量、跨平臺(tái)、高性能、完全零依賴,非常值得學(xué)習(xí)!
1
Oat++ 介紹
要深入了解 Oat++,離不開(kāi)這幾個(gè)網(wǎng)址:
- Oat++ 主頁(yè):https://oatpp.io
- Oat++ 文檔:https://oatpp.io/docs/start
- GitHub 地址:https://github.com/oatpp/oatpp
其主要特性有:
- 隨處運(yùn)行
- Oat++ 沒(méi)有任何依賴性,可以很容易地移植到各種支持的平臺(tái)上(Linux、MacOS、Windows)。
- 構(gòu)建健壯的api
- 使用 Oat++ Simple-API,構(gòu)建靈活而健壯的 API 既簡(jiǎn)單又有趣。
- 處理 500 萬(wàn)個(gè)連接
- 使用 Oat++ Async-API,可以在單個(gè)服務(wù)器上處理超過(guò) 500 萬(wàn)個(gè)并發(fā)連接。
- 訪問(wèn)數(shù)據(jù)庫(kù)
- Oat++ ORM 提供了一種簡(jiǎn)單而統(tǒng)一的方式來(lái)訪問(wèn)數(shù)據(jù)庫(kù)
- 保持代碼一致
- Oat++ 在整個(gè)代碼庫(kù)中依靠對(duì)象映射來(lái)確保 API 和數(shù)據(jù)模型的一致性
- 生成 API 文檔
- 使用 Swagger-UI 和 OpenAPI 3.0.0 自動(dòng)記錄 endpoints
最吸引我的是 HTTP/HTTPS、文件上傳/下載、以及強(qiáng)大的 Swagger API 功能。
2
編譯 Oat++
進(jìn)入 Oat++ 的 GitHub 頁(yè)面,你會(huì)發(fā)現(xiàn) Star 多達(dá) 4K+,貢獻(xiàn)者有 30 多個(gè),且最近幾天還有代碼提交,所以不用擔(dān)心熱度和活躍度,這個(gè)框架一直有人在積極地維護(hù)。
環(huán)境要求
Oat++ 的編譯過(guò)程很簡(jiǎn)單,只需要有基本的開(kāi)發(fā)環(huán)境就行了:
- Git
- 編譯器支持的 C++ 版本 >= 11
- Make
- CMake 版本 >= 3.1
如果沒(méi)有的話,按照下述步驟安裝,以 Ubuntu 為例:
- $ sudo apt install git
- $ sudo apt install cmake
- $ sudo apt install build-essential
編譯安裝
下載 Oat++ 源碼:
- $ git clone https://github.com/oatpp/oatpp.git
隨后,執(zhí)行編譯安裝四部曲:
- $ cd oatpp/
- $ mkdir build && cd build
- $ cmake ..
- $ sudo make && sudo make install
3
示例程序
為了演示 Oat++,我們從最簡(jiǎn)單的“Hello, World!”開(kāi)始!
創(chuàng)建一個(gè) CMake 項(xiàng)目,CMakeLists.txt 配置如下:
- cmake_minimum_required(VERSION 3.1)
- project(helloworld)
- set(CMAKE_CXX_STANDARD 11)
- set(SOURCE_FILES main.cpp handler.h)
- # 查找 oatpp 依賴
- find_package(oatpp REQUIRED)
- add_executable(${PROJECT_NAME} ${SOURCE_FILES})
- # 將目標(biāo)文件與庫(kù)文件進(jìn)行鏈接
- target_link_libraries(${PROJECT_NAME} oatpp::oatpp)
默認(rèn)情況下,Oat++ 會(huì)對(duì)客戶端請(qǐng)求響應(yīng) 404,除此之外什么都不做。
若要添加自定義響應(yīng),必須實(shí)現(xiàn) HttpRequestHandler:
- // handler.h
- #ifndef HANDLER_H
- #define HANDLER_H
- #include "oatpp/web/server/HttpRequestHandler.hpp"
- #define O_UNUSED(x) (void)x;
- // 自定義請(qǐng)求處理程序
- class Handler : public oatpp::web::server::HttpRequestHandler
- {
- public:
- // 處理傳入的請(qǐng)求,并返回響應(yīng)
- std::shared_ptr<OutgoingResponse> handle(const std::shared_ptr<IncomingRequest>& request) override {
- O_UNUSED(request);
- return ResponseFactory::createResponse(Status::CODE_200, "Hello, World!");
- }
- };
- #endif // HANDLER_H
有了處理程序之后,需要通過(guò) Router 將請(qǐng)求路由到它:
- // main.cpp
- #include "oatpp/web/server/HttpConnectionHandler.hpp"
- #include "oatpp/network/tcp/server/ConnectionProvider.hpp"
- #include "oatpp/network/Server.hpp"
- #include "handler.h"
- void run()
- {
- // 為 HTTP 請(qǐng)求創(chuàng)建路由器
- auto router = oatpp::web::server::HttpRouter::createShared();
- // 路由 GET - "/hello" 請(qǐng)求到處理程序
- router->route("GET", "/hello", std::make_shared<Handler>());
- // 創(chuàng)建 HTTP 連接處理程序
- auto connectionHandler = oatpp::web::server::HttpConnectionHandler::createShared(router);
- // 創(chuàng)建 TCP 連接提供者
- auto connectionProvider = oatpp::network::tcp::server::ConnectionProvider::createShared({"localhost", 8000, oatpp::network::Address::IP_4});
- // 創(chuàng)建服務(wù)器,它接受提供的 TCP 連接并將其傳遞給 HTTP 連接處理程序
- oatpp::network::Server server(connectionProvider, connectionHandler);
- // 打印服務(wù)器端口
- OATPP_LOGI("MyApp", "Server running on port %s", connectionProvider->getProperty("port").getData());
- // 運(yùn)行服務(wù)器
- server.run();
- }
- int main()
- {
- // 初始化 oatpp 環(huán)境
- oatpp::base::Environment::init();
- // 運(yùn)行應(yīng)用
- run();
- // 銷(xiāo)毀 oatpp 環(huán)境
- oatpp::base::Environment::destroy();
- return 0;
- }
4
請(qǐng)求驗(yàn)證
運(yùn)行程序,在瀏覽器中訪問(wèn) http://localhost:8000/hello,就會(huì)顯示“Hello, World!”信息了:
或者使用 curl 請(qǐng)求 http://127.0.0.1:8000/hello,效果一樣:
- $ curl http://127.0.0.1:8000/hello
- Hello, World!