C++ 能够响应Http 请求的开源库有哪些?
13 个回答
c++ web framework 很少
随着 c++ 热度升温,c++ 在人工智能 自然语言处理 加快应用。
最近一款国产 paozhu c++ web framework 问世
写业务速度跟脚步语言一样速度,主要是写业务代码优雅,方便 后面附 CURD 例子
-
自带 json 内置 decode encode 支持,支持标准 json 输出,支持 emoji 编码
-
支持多域名网站
-
支持多域名 ssl 服务端
-
支持 http1.1、http2 协议
-
支持 websocket 服务端,
-
框架自带 websocket 推送,支持定时推送到 webscoket 客户端
-
支持同步 httpclient get post
-
框架自带 ORM, 使用链接池方式,目前支持 mysql
-
框架自带线程池,和用户代码运行的线程池
-
框架使用 asio 自带的协程
-
框架特色是 I/O 使用协程池 运行使用线程池
-
框架支持普通文件 gzip br
-
框架解析 URL 和 POST, 解析结果类似 PHP GET POST 方式获取内容
-
集成 sendmail
-
生成二维码 (qrcode), 需要 gd、qrencode 库
目前支持mac linux
具体可以看官方github
#include "orm.h"
#include <chrono>
#include <thread>
#include "md5.h"
#include "func.h"
#include "httppeer.h"
#include "testcurd.h"
namespace http
std::string articlelogin(std::shared_ptr<httppeer> peer)
// step1 show login page
peer->view("login/login");
return "";
std::string articleloginpost(std::shared_ptr<httppeer> peer)
// step2
// get login/login post field
httppeer &client = peer->getpeer();
std::string username = client.post["username"].to_string();
std::string password = client.post["password"].to_string();
auto users = orm::cms::User();
std::string md5string;
md5string = md5(password);
users.where("name=", username).whereAnd("password=", md5string).limit(1).fetch();
// view orm create sql
// client<<"<p>"<<users.sqlstring<<"</p>";
if (users.getUserid() > 0)
// save session,other page get int userid= client.session["userid"].to_int();
client.session["userid"] = users.getUserid();
client.save_session();
client.goto_url("/cms/list");
return "";
client.goto_url("/cms/login",3,"用户名或密码错误!");
return "";
catch (std::exception &e)
client << "<p>" << e.what() << "</p>";
return "";
return "";
std::string articlelist(std::shared_ptr<httppeer> peer)
// step3 content list
httppeer &client = peer->getpeer();
int userid = client.session["userid"].to_int();
if (userid == 0)
// client.goto_url("/cms/login");
client.val["msg"] = "<a href=\"/cms/login\">Please login </a>";
auto articles = orm::cms::Article();
int page = client.get["page"].to_int();
if (page < 0)
page = 0;
page = page * 20;
articles.where("isopen=1").order(" aid desc ").limit(page, 20).fetch();
// 也可以直接返回OBJ_VALUE 对象; 不过正常业务会要处理下结果集
// You can also return the OBJ_VALUE object directly; but normal business process will need to process the result set
client.val["list"].set_array();
if (articles.size() > 0)
for (auto &bb : articles)
OBJ_ARRAY item;
item["aid"] = bb.aid;
item["title"] = bb.title;
item["createtime"] = bb.createtime;
item["summary"] = bb.summary;
// client<<"<p><a href=\"/cms/show?id="<<bb.aid<<"\">"<<bb.title<<"</a> "<<bb.createtime<<" </p>";
client.val["list"].push(std::move(item));
peer->view("cms/list");
return "";
std::string articleshow(std::shared_ptr<httppeer> peer)
// step4
httppeer &client = peer->getpeer();
auto articles = orm::cms::Article();
int aid = client.get["id"].to_int();
articles.where("isopen=1").where(" aid=", aid).limit(1).fetch();
client.val["title"] = articles.getTitle();
client.val["content"] = articles.getContent();
peer->view("cms/show");
return "";
std::string articleedit(std::shared_ptr<httppeer> peer)
// same the show content
httppeer &client = peer->getpeer();
auto articles = orm::cms::Article();
int aid = client.get["id"].to_int();
articles.where("isopen=1").where(" aid=", aid).limit(1).fetch();
client.val["title"] = articles.getTitle();
client.val["content"] = html_encode(articles.getRefContent());
client.val["aid"] = articles.getAid();
peer->view("cms/edit");
return "";
std::string articleeditpost(std::shared_ptr<httppeer> peer)
httppeer &client = peer->getpeer();
std::string title = client.post["title"].to_string();
std::string content = client.post["content"].to_string();
unsigned int aid = client.post["aid"].to_int();
auto articles = orm::cms::Article();
// articles.where("isopen=1").where(" aid=",aid).limit(1).fetch();
// articles.data.aid=aid;
// articles.data.title=title;
// articles.setAid(aid);
articles.setTitle(title);
// articles.setTitle("直接标题");
articles.setContent(content);
articles.where(" aid=", aid);
int effectnum = 0;
effectnum = articles.update("title,content");
catch (std::exception &e)
client << "<p>" << articles.sqlstring << "</p>";
client << "<p>" << e.what() << "</p>";
return "";
if (effectnum > 0)
client.goto_url("/cms/list", 3, "内容已经更新");
return "";
client.goto_url("/cms/list", 3, "更新出错(error)");
return "";
return "";
std::string articleadd(std::shared_ptr<httppeer> peer)
httppeer &client = peer->getpeer();
peer->view("cms/add");
return "";
std::string articleaddpost(std::shared_ptr<httppeer> peer)
httppeer &client = peer->getpeer();
std::string title = client.post["title"].to_string();
std::string content = client.post["content"].to_string();
unsigned int aid = 0;
auto articles = orm::cms::Article();
// articles.data.aid=aid;
// articles.data.title=title;
// articles.setAid(aid);
articles.setIsopen(1);
articles.setCreatetime(date("%Y-%m-%d %X")); // Y-m-d H:i:s
articles.setAddtime(timeid()); // unix timestamp
articles.setAddip(client.client_ip); // client ip
articles.setTitle(title);
// articles.setTitle("直接标题");
articles.setContent(content);
int effectnum = 0;
effectnum = articles.save();
aid = articles.getAid();
client << "<p>新(new)id " << aid << " 或 新(new)id " << effectnum << "</p>";
catch (std::exception &e)
client << "<p>" << articles.sqlstring << "</p>";
client << "<p>" << e.what() << "</p>";
return "";
if (effectnum > 0)
client.goto_url("/cms/list", 3, "内容已经添加");
return "";
client.goto_url("/cms/list", 3, "添加出错(error)");
return "";
return "";
std::string articledelete(std::shared_ptr<httppeer> peer)
httppeer &client = peer->getpeer();
unsigned int aid = client.get["id"].to_int();
auto articles = orm::cms::Article();
// 可以先查询是否存在或有权限之类
// articles.where("isopen=1").where(" aid=",aid).limit(1).fetch();
int effectnum = 0;
effectnum = articles.remove(aid);
catch (std::exception &e)
client << "<p>" << articles.sqlstring << "</p>";
client << "<p>" << e.what() << "</p>";
return "";
if (effectnum > 0)
client.goto_url("/cms/list", 3, "内容已经删除");
return "";
client.goto_url("/cms/list", 3, "删除出错(error)");
return "";
return "";
}
更看官方 controller 例子
推荐一下最为简单高效的c++11异步restful网络框架。
像gin一样开发性能更好的c++服务器。
项目地址 : GitHub - wfrest/wfrest: C++ Web Framework REST API
wfrest 是基于当前最火最简洁好用的c++异步网络库 workflow。
项目地址 : https:// github.com/sogou/workfl ow
workflow虽然也 可以用作 web framework ,只是他的侧重点是做高性能服务,任务流管理,名称服务这些。而做web framework需要的一些像route,cookie等接口。所以对workflow进行二次开发进行拓展,能使得 workflow像 Golang 的gin框架,python的flask一样快速的开发。
http服务端最简版
我们以下简单的接口可以完成发送数据,发送文件,发送json等功能。其中所有的功能都是异步,对于文件读取非常高效。
#include "wfrest/HttpServer.h"
using namespace wfrest;
int main()
HttpServer svr;
// 发送数据
svr.GET("/hello", [](const HttpReq *req, HttpResp *resp)
resp->String("world\n");
// 获取http 请求的数据
svr.POST("/post", [](const HttpReq *req, HttpResp *resp)
std::string& body = req->body();
fprintf(stderr, "post data : %s\n", body.c_str());
// 文件读写都是异步
// 发送文件
svr.GET("/file", [](const HttpReq *req, HttpResp *resp)
resp->File("todo.txt");
// 上传文件
svr.POST("/upload", [](const HttpReq *req, HttpResp *resp)
std::string& body = req->body();
resp->Save("test.txt", std::move(body));
// 发送json数据
svr.GET("/json", [](const HttpReq *req, HttpResp *resp)
std::string json = R"(
"numbers": [1, 2, 3]
resp->Json(json);
if (svr.start(8888) == 0)
getchar()
svr.stop();
} else
fprintf(stderr, "Cannot start server");
exit(1);
return 0;
能够多种形式,灵活获取路径中的参数
svr.GET("/wildcast/{name}/action*", [](const HttpReq *req, HttpResp *resp)
const std::string& name = req->param("name");
const std::string& match_path = req->match_path();
简单接口获取x-www-form-urlencoded,multipart/form-data 数据
svr.POST("/urlencoded", [](const HttpReq *req, HttpResp *resp)
std::map<std::string, std::string> &form_kv = req->form_kv();
svr.POST("/multipart", [](const HttpReq *req, HttpResp *resp)
const Form &form = req->form();
简单的接口提供静态文件服务
svr.Static("/static", "./www/static");
svr.Static("/public", "./www");
设置并获取cookie
svr.GET("/cookie", [](const HttpReq *req, HttpResp *resp)
const std::map<std::string, std::string> &cookie = req->cookies();
if(cookie.empty()) // no cookie
HttpCookie cookie;
cookie.set_path("/").set_http_only(true);
resp->add_cookie(std::move(cookie));
resp->String("Set Cookie\n");
还能够利用blueprint, 使得代码更加模块化
// 写在其他文件/模块中
void set_admin_bp(BluePrint &bp)
bp.GET("/page/new/", [](const HttpReq *req, HttpResp *resp)
fprintf(stderr, "New page\n");
bp.GET("/page/edit/", [](const HttpReq *req, HttpResp *resp)
fprintf(stderr, "Edit page\n");
int main()
HttpServer svr;
BluePrint admin_bp;
set_admin_bp(admin_bp);
svr.register_blueprint(admin_bp, "/admin");
在workflow中,对于计算型的任务有着巨大的优势,所以我们还提供了计算型的handler
// 传入第二个计算队列index,就添加入了计算队列之中
svr.GET("/compute_task", 1, [](const HttpReq *req, HttpResp *resp)
ComputeFunc();
workflow作为万能异步客户端。目前支持http,redis,mysql和kafka等多种协议,为了很好的使用户利用workflow的特性,可以使用Series Handler, 将这些任务都串如任务流中完成
svr.GET("/series", [](const HttpReq *req, HttpResp *resp, SeriesWork* series)
// 此处可以是redis task, mysql task, http task, kafka task, 计算task,文件task....
auto *timer = WFTaskFactory::create_timer_task(5000000, [](WFTimerTask *) {
printf("timer task complete(5s).\n");
// push_back加入series就串行处理
series->push_back(timer);
还可以利用非常酷炫的dag图结构完成更为复杂的任务
svr.GET("/series", [](const HttpReq *req, HttpResp *resp, SeriesWork* series)
WFGraphTask *graph = WFTaskFactory::create_graph_task([](WFGraphTask *) {
fprintf(stderr, "Graph task complete.");
WFHttpTask *start_task = WFTaskFactory::create_http_task("http://www.baidu.com", 4, 2,
http_callback);
WFGraphNode& a = graph->create_graph_node(start_task);
WFGraphNode& b = graph->create_graph_node(pwork1);
WFGraphNode& c = graph->create_graph_node(pwork2);
/* Build the graph */
a-->b;
a-->c;
series->push_back(graph);
还支持AOP(面向切面編程)
// Logging aspect
struct LogAop : public Aspect
bool before(const HttpReq *req, HttpResp *resp) override
fprintf(stderr, "before \n");
return true;
// 'after()' should be called after reply
bool after(const HttpReq *req, HttpResp *resp) override
fprintf(stderr, "After log\n");
return true;
int main()
svr.GET("/aop", [](const HttpReq *req, HttpResp *resp)