排行來源:https://www.techempower.com/benchmarks/
今天來學習一下由國人開發的瘋狂刷棒的api 框架:drogon
0x00 準備C++WEB開發環境
從源碼安裝,生成項目配置工具。
git clone [https://github.com/an-tao/drogon](https://github.com/an-tao/drogon)
cd drogon
git submodule update --init
mkdir build
# gcc 12以上,開啓協程支持
cmake .. -DCMAKE_CXX_FLAGS="-std=c++20"
make && sudo make install
中途缺啥,直接brew install
,大概率可直接解決
安裝完成後,可以使用命令行工具drogon_ctl
快捷命令創建和維護代碼。
也可以使用別名:dg_ctl
查看基礎用法:
$ drogon_ctl help create
Use create command to create some source files of drogon webapp
Usage:drogon_ctl create <view|controller|filter|project|model> [-options] <object name>
drogon_ctl create view <csp file name> [-o <output path>] [-n <namespace>] [--path-to-namespace] //create HttpView source files from csp files, namespace is prefixed of path-to-namespace
drogon_ctl create controller [-s] <[namespace::]class_name> //create HttpSimpleController source files
drogon_ctl create controller -h <[namespace::]class_name> //create HttpController source files
drogon_ctl create controller -w <[namespace::]class_name> //create WebSocketController source files
drogon_ctl create controller -r <[namespace::]class_name> [--resource=...]//create restful controller source files
drogon_ctl create filter <[namespace::]class_name> //create a filter named class_name
drogon_ctl create plugin <[namespace::]class_name> //create a plugin named class_name
drogon_ctl create project <project_name> //create a project named project_name
drogon_ctl create model <model_path> [--table=<table_name>] [-f]//create model classes in model_path
0x01 創建第一個項目
- 創建項目
drogon_ctl create project dc_hello
使用CLion
打開此項目是可以直接運行的,訪問本機 80 服務,返回404.
- 添加一個 index響應
調整main.cpp
, 增加一個handler響應處理。
#include <drogon/drogon.h>
using namespace drogon;
int main() {
drogon::app().addListener("0.0.0.0", 80);
drogon::app().registerHandler("/",
[](const HttpRequestPtr &req, std::function<void(const HttpResponsePtr &)> &&callback) {
auto resp = HttpResponse::newHttpResponse();
resp->setBody("hello world");
callback(resp);
});
drogon::app().run();
return 0;
}
- 新增一個Controller,用於處理複雜rest api處理
開始之前,先看一個url例子:
分解一下:
-
api/v1
: 在drogon
中, 是以namespace
的形式存在 -
user
:Controller
處理類,也符合Rest
中實體的名稱定義 -
get
: 在Controller
上的某個具體行爲
接下來,開始操作
cd controllers
drogon_ctl create controller -h api::v1::User
生成文件後,手動在CMakeFiles.txt 中加上 .cc 文件。
# 啓動 協程,在project 前添加
set(CMAKE_CXX_STANDARD 20)
# 添加文件
add_executable(${PROJECT_NAME} main.cc controllers/api_v1_User.cc)
接下來,修改兩個文件:
- .h
#pragma once
#include <drogon/HttpController.h>
using namespace drogon;
namespace api::v1 {
class User : public drogon::HttpController<User> {
public:
METHOD_LIST_BEGIN
METHOD_ADD(User::get, "/get", Get);
METHOD_LIST_END
void get(const HttpRequestPtr &req, std::function<void(const HttpResponsePtr &)> &&callback);
};
}
- .cc
#include "api_v1_User.h"
using namespace api::v1;
void User::get(const HttpRequestPtr &req, std::function<void(const HttpResponsePtr &)> &&callback) {
Json::Value rst;
rst["code"] = 0;
rst["message"] = "ok";
auto resp = HttpResponse::newHttpJsonResponse(rst);
callback(resp);
}
編譯運行測試接口:
$ curl localhost/api/v1/user/get
{"code":0,"message":"ok"}
0x02 多種參數獲取方式
一、URL參數
直接上代碼:
// 增加URI配置, {1}對應方法後面的第一個參數
METHOD_ADD(User::get_info, "/info/{1}", Get);
void get_info(const HttpRequestPtr &req, std::function<void(const HttpResponsePtr &)> &&callback, std::string name);
void User::get_info(const HttpRequestPtr &req,
std::function<void(const HttpResponsePtr &)> &&callback,
std::string name) {
Json::Value rst;
rst["code"] = 0;
rst["message"] = "hello: " + name;
auto resp = HttpResponse::newHttpJsonResponse(rst);
callback(resp);
}
效果 :
$ curl localhost/api/v1/user/info/demo
{"code":0,"message":"hello: demo"}
二、query參數
METHOD_ADD(User::get_detail, "/detail?name={1}", Get);
void get_detail(const HttpRequestPtr &req, std::function<void(const HttpResponsePtr &)> &&callback, std::string name);
void User::get_detail(const HttpRequestPtr &req,
std::function<void(const HttpResponsePtr &)> &&callback,
std::string name) {
Json::Value rst;
rst["code"] = 0;
rst["message"] = "detail: " + name;
auto resp = HttpResponse::newHttpJsonResponse(rst);
callback(resp);
}
上面兩種,感覺是同一類處理方法,通過類似正則的方式去獲取相應的參數。
三、json Body參數
編寫一個POST方式,提交json的接口例:
METHOD_ADD(User::add, "/add", Post);
void add(const HttpRequestPtr &req, std::function<void(const HttpResponsePtr &)> &&callback);
void User::add(const HttpRequestPtr &req, std::function<void(const HttpResponsePtr &)> &&callback) {
auto param = req->getJsonObject();
Json::Value rst;
rst["code"] = 0;
if (param) {
auto name = (*param)["name"].asString();
rst["message"] = "user added :" + name;
}
auto resp = HttpResponse::newHttpJsonResponse(rst);
callback(resp);
}
驗證:
$ curl -XPOST localhost/api/v1/user/add -d '{"name":"Cook"}' -H"content-type:application/json"
{"code":0,"message":"user added :Cook"}
四、json請求參數,自動轉爲Bean
在.h文件中, 需要預定義一個轉換方法:
namespace api::v1 {
struct UserParam {
std::string name;
std::string email;
};
}
namespace drogon {
template<>
inline api::v1::UserParam fromRequest(const HttpRequest &req) {
auto json = req.getJsonObject();
api::v1::UserParam param;
if (json) {
param.name = (*json)["name"].asString();
param.email = (*json)["email"].asString();
}
return param;
}
}
然後編寫路由匹配和方法定義:
METHOD_ADD(User::add_user, "/add/user", Post);
// 注意: 這裏第一個參數是轉換後的結構體對象,可以自動提取轉換
void add_user(UserParam &&pUserParam, std::function<void(const HttpResponsePtr &)> &&callback) const;
void User::add_user(UserParam &&pUserParam, std::function<void(const HttpResponsePtr &)> &&callback) const {
Json::Value rst;
rst["code"] = 0;
rst["message"] = pUserParam.name + ":" + pUserParam.email;
auto resp = HttpResponse::newHttpJsonResponse(rst);
callback(resp);
}
0x03 小結
至此,已經具體API開發的基本能力了, 後續增加其他體驗:
- redis
- mysql
- 日誌
- 切面
最後,也是最重要的官方學習文檔:
https://github.com/drogonframework/drogon-docs/blob/master/CHN-03-%E5%BF%AB%E9%80%9F%E5%BC%80%E5%A7%8B.md
0x04 Mac下協程編譯支持
brew install gcc@12
修改cmake文件中的編譯器
SET(CMAKE_C_COMPILER /opt/homebrew/bin/gcc-12)
SET(CMAKE_CXX_COMPILER /opt/homebrew/bin/g++-12)