Drogon是基于非阻塞I/O、零拷贝、全异步设计的现代C++ Web框架,适合低延迟高吞吐内部服务、C++生态直曝HTTP接口及ABI敏感场景;不适合快速原型或同步SDK重度依赖项目。

drogon 是什么,适合什么场景
drogon 不是“C++ 的 Express”,它更接近于 Rust 的 Actix 或 Go 的 Gin:基于非阻塞 I/O、零拷贝、全异步设计的现代 C++ Web 框架。它默认使用 libevent(也可切换为 libuv 或 trantor 自研 event loop),所有 HTTP 处理都在事件循环中完成,不依赖线程池做请求分发——这意味着你能轻松支撑数万并发连接,但前提是业务逻辑本身不阻塞。
它适合:需要低延迟、高吞吐的内部服务(如游戏网关、实时配置下发、设备上报聚合);已有 C++ 生态(如音视频处理、算法库)需直接暴露 HTTP 接口;对 ABI 稳定性和部署体积敏感(单二进制、无运行时依赖)。
不适合:快速原型或 CRUD 后台管理(相比 Django/Flask,模板、ORM、Admin 都要自己搭);重度依赖同步第三方 SDK(比如某些只提供阻塞 API 的数据库驱动)。
初始化项目与路由定义的关键写法
用 drogon_ctl 创建项目后,别急着写 handler——先确认 app().registerSyncAdvice() 或 app().registerAsyncAdvice() 是否被误加,它们会全局拦截所有请求,新手常因忘记移除调试用的 advice 导致 500 或响应为空。
立即学习“C++免费学习笔记(深入)”;
路由定义推荐用代码方式(而非配置文件),便于 IDE 跳转和编译期检查:
// 在 main() 中注册
app().registerHandler("/api/user/{id}",
[](const HttpRequestPtr& req, std::function &&callback, const std::string &id) {
auto resp = HttpResponse::newHttpResponse();
resp->setBody("user id: " + id);
callback(resp);
},
{HttpMethod::Get});
注意点:
-
{id}是路径参数,必须用大括号包裹,且不能含斜杠;若需匹配多级路径(如/files/{path+}),得用addPathPattern()手动注册 - handler 函数签名必须严格匹配:三个参数顺序、类型、右值引用修饰符缺一不可,否则编译报错信息极不友好(常见错误:
no matching function for call to 'registerHandler') - 不要在 handler 里直接
return,必须调用callback(),否则请求永远挂起
数据库连接与异步查询的正确姿势
drogon 自带 DbClient 封装(基于 PostgreSQL 的 libpq 或 MySQL 的 mysqlclient),但它**不是线程安全的**,也不能跨 event loop 使用。最常见错误是:在构造函数里 new 一个 DbClient 存为全局变量,然后在多个 handler 中并发调用 execSqlAsync() —— 这会导致连接状态错乱甚至 core dump。
GarbageSort垃圾识别工具箱是一个基于uni-app开发的微信小程序,使用SpringBoot2搭建后端服务,使用Swagger2构建Restful接口文档,实现了文字查询、语音识别、图像识别其垃圾分类的功能。前端:微信小程序 采用 uni-app 开发框架,uni-app 是一个使用 Vue.js 开发所有前端应用的框架,开发者编写一套代码,可发布到iOS、Android、H5、以及各
正确做法:
- 用
app().getDbClient("default")获取 client,它由 drogon 内部管理生命周期和连接池 - 所有 SQL 调用必须用
execSqlAsync(),绝不用execSql()(后者会阻塞 event loop) - 回调中处理结果时,确保
result.size()检查后再取字段,空结果集下result[0]["name"]会抛std::out_of_range
示例:
auto client = app().getDbClient("default");
client->execSqlAsync("SELECT id,name FROM users WHERE id=$1",
[callback](const DbClient::Result &result) {
auto resp = HttpResponse::newHttpResponse();
if (!result.empty()) {
Json::Value json;
json["id"] = result[0]["id"].asInt64();
json["name"] = result[0]["name"].asString();
resp->setBody(json.toStyledString());
} else {
resp->setStatusCode(k404NotFound);
}
callback(resp);
},
id);
静态文件与 HTTPS 部署的硬性约束
drogon 内置静态文件服务(app().setStaticFileDirectory())仅支持单目录映射,不支持按扩展名设置 MIME 类型或自定义缓存头。如果你需要 /assets/js/app.js 返回 application/javascript 且带 Cache-Control: public, max-age=31536000,就得自己写 handler 拦截并手动设置 resp->addHeader("Cache-Control", "...") 和 resp->setContentTypeCode(...)。
HTTPS 方面,drogon 要求证书和私钥必须是 PEM 格式,且私钥**不能加密**(即不能有 DEK-Info 头)。用 OpenSSL 生成时务必加 -nodes 参数:
openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 -nodes
否则启动时日志只显示 SSL context initialization failed,没有任何具体错误码或行号,排查极耗时间。
生产部署建议反向代理(Nginx/Traefik)终止 HTTPS,drogon 只跑 HTTP——既规避证书管理复杂度,又能复用 Nginx 的 gzip、限流、访问日志等能力。drogon 的 app().setSSLFiles() 更适合内网直连或 PoC 场景。









