wfrest
wfrest是一个基于workflow的C++服务端框架,它简化了workflow服务端的使用方法,并且还提供了很 多辅助函数,包括URI路由、查询参数获取、表单数据获取等等。
Github地址 https://github.com/wfrest/wfrest/blob/main/README_cn.md
安装wfrest的方法和workflow差不多:
bash
mkdir build
cd build
cmake ..
make
sudo make install
sudo ldconfig
下面是使用wfrest来解析请求示例
cpp
#include <iostream>
using std::cout;
using std::endl;
#include <signal.h>
#include <wfrest/HttpServer.h>
#include <workflow/WFFacilities.h>
static WFFacilities::WaitGroup waitGroup(1);
void sighandler(int num) {
printf("sig %d is coming\n", num); // 将计数器的值减1
waitGroup.done();
}
int main() {
using std::string;
signal(SIGINT, sighandler);
using namespace wfrest;
HttpServer httpserver;
httpserver.GET("/wfrest/test0", [](const HttpReq *, HttpResp *resp) {
// 使用workflow的方式设置响应
resp->append_output_body("hello, wfrest client"); });
httpserver.GET("/wfrest/query", [](const HttpReq *req, HttpResp *resp) {
// uri的查询参数部分
cout << "username:" << req->query("username") << endl;
auto queryList = req->query_list();
for (auto &query : queryList) {
cout << query.first << ": " << query.second << endl;
}
resp->append_output_body("hello, wfrest client1");
});
httpserver.POST("/wfrest/body", [](const HttpReq *req, HttpResp *resp) {
// 请求体
string body = req->body();
cout << "body:" << body << endl;
resp->append_output_body("hello, wfrest client");
});
httpserver.POST("/wfrest/urlencoded", [](const HttpReq *req, HttpResp *resp) {
// URLENCODED类型的请求体
if (req->content_type() == APPLICATION_URLENCODED) {
auto formKV = req->form_kv();
for (auto &elem : formKV) {
cout << elem.first << ": " << elem.second << endl;
}
}
resp->append_output_body("hello, wfrest client");
});
httpserver.POST("/wfrest/formdata", [](const HttpReq *req, HttpResp *resp) {
// form_data类型的请求体
if (req->content_type() == MULTIPART_FORM_DATA) {
auto form = req->form();
for (auto &elem : form) {
cout << elem.first << ": " << elem.second.first << endl;
cout << elem.second.second << endl;
}
}
resp->append_output_body("hello, wfrest client");
});
if (httpserver.track().start(1234) == 0) {
// 列出当前服务器上部署的服务
httpserver.list_routes();
waitGroup.wait();
httpserver.stop();
} else {
printf("HttpServer start failed.\n");
}
return 0;
}
wfrest也支持更丰富的功能:
cpp
#include <iostream>
#include <vector>
using std::cout;
using std::endl;
#include <signal.h>
#include <wfrest/HttpServer.h>
#include <wfrest/MysqlUtil.h>
#include <workflow/WFFacilities.h>
static WFFacilities::WaitGroup waitGroup(1);
void sighandler(int num) {
printf("sig %d is coming\n", num);
// 将计数器的值减1
waitGroup.done();
}
int main() {
using std::string;
signal(SIGINT, sighandler);
using namespace wfrest;
HttpServer httpserver;
httpserver.GET("/wfrest/test0", [](const HttpReq *, HttpResp *resp) {
// String可以自动设置首部字段
resp->String("hello,wfrest client2");
});
// 部署静态资源
httpserver.GET("/wfrest/file", [](const HttpReq *, HttpResp *resp) { resp->File("postform.html"); });
// 响应JSON
httpserver.GET("/wfrest/json", [](const HttpReq *, HttpResp *resp) {
Json data;
data["username"] = "liubei";
data["password"] = "123";
resp->Json(data);
});
// MySQL默认结果
httpserver.GET("/wfrest/mysql0", [](const HttpReq *, HttpResp *resp) {
string url("mysql://root:123@localhost");
string sql("select * from mycloud.tbl_user_token");
resp->MySQL(url, sql);
});
// MySQL的Json结果
httpserver.GET("/wfrest/mysql1", [](const HttpReq *, HttpResp *resp) {
string url("mysql://root:123@localhost");
string sql("select * from mycloud.tbl_user_token");
// json指针指向的就是MySQL的结果集
resp->MySQL(url, sql, [resp](Json *json) {
string msg = (*json)["result_set"][0]["rows"][0][1];
resp->String(msg);
});
});
// MySQL cursor
httpserver.GET("/wfrest/mysql2", [](const HttpReq *, HttpResp *resp) {
string url("mysql://root:123@localhost");
string sql("select * from mycloud.tbl_user_token");
using namespace protocol;
// pcursor指针指向的就是MySQL的结果集的迭代器
resp->MySQL(url, sql, [resp](MySQLResultCursor *pcursor) {
std::vector<std::vector<MySQLCell>> matrix;
pcursor->fetch_all(matrix);
string msg = matrix[0][2].as_string();
resp->String(msg);
});
});
// 在wfrest中显式使用序列
httpserver.GET("/wfrest/series", [](const HttpReq *, HttpResp *resp, SeriesWork *series) {
auto timerTask = WFTaskFactory::create_timer_task(1000 * 1000, [resp](WFTimerTask *) {
printf("timerCallback is running.\n");
resp->String("timer callback");
});
series->push_back(timerTask);
});
// 序列配合mysql任务
httpserver.GET("/wfrest/mysql3", [](const HttpReq *, HttpResp *httpResp, SeriesWork *series) {
string url("mysql://root:123@localhost");
auto mysqlTask = WFTaskFactory::create_mysql_task(url, 1, [httpResp](WFMySQLTask *mysqltask) {
// 0. 对任务的状态进行检测
int state = mysqltask->get_state();
int error = mysqltask->get_error();
if (state != WFT_STATE_SUCCESS) {
printf("%s\n", WFGlobal::get_error_string(state, error));
return;
}
// 1. 检测SQL语句是否存在语法错误
auto resp = mysqltask->get_resp();
if (resp->get_packet_type() == MYSQL_PACKET_ERROR) {
printf("ERROR %d: %s\n", resp->get_error_code(), resp->get_error_msg().c_str());
return;
}
printf("sql sentence is ok.\n");
using namespace protocol;
MySQLResultCursor cursor(resp);
if (cursor.get_cursor_status() == MYSQL_STATUS_OK) {
printf("Query OK. %llu row affected.\n", cursor.get_affected_rows());
} else if (cursor.get_cursor_status() == MYSQL_STATUS_GET_RESULT) {
// 读操作
std::vector<std::vector<MySQLCell>> matrix;
cursor.fetch_all(matrix);
string msg = matrix[1][1].as_string();
httpResp->String(msg);
}
});
string sql("select * from mycloud.tbl_user_token");
mysqlTask->get_req()->set_query(sql);
series->push_back(mysqlTask);
});
if (httpserver.track().start(1234) == 0) {
// 列出当前服务器上部署的服务
httpserver.list_routes();
waitGroup.wait();
httpserver.stop();
} else {
printf("HttpServer start failed.\n");
}
return 0;
}