Skip to content

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;
}