概述
Drogon是一个基于C++14/17的HTTP应用框架。Drogon可用于使用C++轻松构建各种类型的网络应用服务器程序。Drogon是美国电视剧《权力的游戏》中一条龙的名字,我非常喜欢。
Drogon是一个跨平台的框架,它支持Linux、macOS、FreeBSD、OpenBSD、HaikuOS和Windows。它的主要特点如下。
- 使用基于epoll的非阻塞I/O网络库(macOS/FreeBSD下为kqueue),提供高并发、高性能的网络IO,更多细节请访问TFB测试结果。
- 提供一个完全异步的编程模式。
- 支持Http1.0/1.1(服务器端和客户端)。
- 基于模板,实现了简单的反射机制,将主程序框架、控制器和视图完全解耦。
- 支持cookies和内置会话。
- 支持后端渲染,控制器生成的数据给视图生成Html页面。视图由CSP模板文件描述,C++代码通过CSP标签嵌入到Html页面。而drogon命令行工具自动生成C++代码文件进行编译。
- 支持视图页面动态加载(运行时动态编译和加载)。
- 提供从路径到控制器处理程序的方便灵活的路由解决方案。
- 支持过滤链,方便在处理HTTP请求前执行统一的逻辑(如登录验证、Http Method约束验证等)。
- 支持https(基于OpenSSL)。
- 支持WebSocket(服务器端和客户端)。
- 支持JSON格式的请求和响应,对Restful API应用开发非常友好。
- 支持文件下载和上传。
- 支持gzip、brotli压缩传输。
- 支持管道化。
- 提供一个轻量级的命令行工具drogon_ctl,以简化Drogon中各种类的创建和视图代码的生成。
- 支持基于非阻塞I/O的异步读写数据库(PostgreSQL和MySQL(MariaDB)数据库)。
- 支持基于线程池的异步读写 sqlite3 数据库。
- 支持Redis的异步读和写。
- 支持ARM架构。
- 提供方便的轻量级ORM实现,支持常规对象到数据库的双向映射。
- 支持插件,可以在加载时由配置文件安装。
- 支持带有内置连接点的AOP。
- 支持C++ Coroutines
一个非常简单的例子
与大多数C++框架不同,Drogon应用程序的主程序可以保持干净和简单。Drogon使用一些技巧将控制器与主程序解耦。控制器的路由设置可以通过宏或配置文件完成。
下面是一个典型的Drogon应用程序的主程序。
#include <drogon/drogon.h>
using namespace drogon;
int main()
{
app().setLogPath("./")
.setLogLevel(trantor::Logger::kWarn)
.addListener("0.0.0.0", 80)
.setThreadNum(16)
.enableRunAsDaemon()
.run();
}
它可以通过使用配置文件进一步简化,如下所示。
#include <drogon/drogon.h>
using namespace drogon;
int main()
{
app().loadConfigFile("./config.json").run();
}
Drogon提供了一些接口,可以直接在main()函数中添加控制器逻辑,例如,用户可以在Drogon中注册一个类似的处理器。
app().registerHandler("/test?username={name}",
[](const HttpRequestPtr& req,
std::function<void (const HttpResponsePtr &)> &&callback,
const std::string &name)
{
Json::Value json;
json["result"]="ok";
json["message"]=std::string("hello,")+name;
auto resp=HttpResponse::newHttpJsonResponse(json);
callback(resp);
},
{Get,"LoginFilter"});
虽然这样的接口看起来很直观,但它们并不适合复杂的业务逻辑场景。假设有几十个甚至几百个处理程序需要在框架中注册,那么在各自的类中分别实现它们不是更好的做法吗?所以除非你的逻辑非常简单,否则我们不建议使用上述接口。相反,我们可以创建一个HttpSimpleController,如下所示。
/// The TestCtrl.h file
#pragma once
#include <drogon/HttpSimpleController.h>
using namespace drogon;
class TestCtrl:public drogon::HttpSimpleController<TestCtrl>
{
public:
void asyncHandleHttpRequest(const HttpRequestPtr& req, std::function<void (const HttpResponsePtr &)> &&callback) override;
PATH_LIST_BEGIN
PATH_ADD("/test",Get);
PATH_LIST_END
};
/// The TestCtrl.cc file
#include "TestCtrl.h"
void TestCtrl::asyncHandleHttpRequest(const HttpRequestPtr& req,
std::function<void (const HttpResponsePtr &)> &&callback)
{
//write your application logic here
auto resp = HttpResponse::newHttpResponse();
resp->setBody("<p>Hello, world!</p>");
resp->setExpiredTime(0);
callback(resp);
}
上述大多数程序可以由drogon提供的命令行工具drogon_ctl (命令是drogon_ctl create controller TestCtrl )自动生成。用户所需要做的就是添加自己的业务逻辑。在这个例子中,当客户端访问http://ip/test URL时,控制器返回一个Hello, world! 字符串。
对于JSON格式的响应,我们创建控制器的方法如下。
/// The header file
#pragma once
#include <drogon/HttpSimpleController.h>
using namespace drogon;
class JsonCtrl : public drogon::HttpSimpleController<JsonCtrl>
{
public:
void asyncHandleHttpRequest(const HttpRequestPtr &req, std::function<void(const HttpResponsePtr &)> &&callback) override;
PATH_LIST_BEGIN
//list path definitions here;
PATH_ADD("/json", Get);
PATH_LIST_END
};
/// The source file
#include "JsonCtrl.h"
void JsonCtrl::asyncHandleHttpRequest(const HttpRequestPtr &req,
std::function<void(const HttpResponsePtr &)> &&callback)
{
Json::Value ret;
ret["message"] = "Hello, World!";
auto resp = HttpResponse::newHttpJsonResponse(ret);
callback(resp);
}
让我们更进一步,用HttpController类创建一个演示的RESTful API,如下所示(省略源文件)。
/// The header file
#pragma once
#include <drogon/HttpController.h>
using namespace drogon;
namespace api
{
namespace v1
{
class User : public drogon::HttpController<User>
{
public:
METHOD_LIST_BEGIN
//use METHOD_ADD to add your custom processing function here;
METHOD_ADD(User::getInfo, "/{id}", Get); //path is /api/v1/User/{arg1}
METHOD_ADD(User::getDetailInfo, "/{id}/detailinfo", Get); //path is /api/v1/User/{arg1}/detailinfo
METHOD_ADD(User::newUser, "/{name}", Post); //path is /api/v1/User/{arg1}
METHOD_LIST_END
//your declaration of processing function maybe like this:
void getInfo(const HttpRequestPtr &req, std::function<void(const HttpResponsePtr &)> &&callback, int userId) const;
void getDetailInfo(const HttpRequestPtr &req, std::function<void(const HttpResponsePtr &)> &&callback, int userId) const;
void newUser(const HttpRequestPtr &req, std::function<void(const HttpResponsePtr &)> &&callback, std::string &&userName);
public:
User()
{
LOG_DEBUG << "User constructor!";
}
};
} // namespace v1
} // namespace api
如你所见,用户可以使用HttpController ,同时映射路径和参数。这是创建RESTful API应用的一种非常方便的方式。
此外,你还可以发现,所有的处理程序接口都是异步模式,响应由一个回调对象返回。这种设计是出于性能的考虑,因为在异步模式下,drogon应用程序可以用少量的线程处理大量的并发请求。
在编译了上述所有的源文件后,我们得到了一个非常简单的Web应用程序。这是一个好的开始。欲了解更多信息,请访问wiki或DocsForge
贡献
我们欢迎每一个贡献。请参考贡献指南以了解更多信息。
