目录
说明/前言
~~~~~~~~
- cpp-httplib是一个简单易用, 跨平台, 开发快速, 仅头文件的c++ http库, 只需要把一个头文件包含到你的代码里, 就可以用很少的代码完成一个http server, 但它仍有一些不足之处, 比如会阻塞你的主线程(cpp-httplib的github地址)
~~~~~~~~
- 在不影响cpp-httplib原生代码的基础上, 对其进行了进一步的封装, 且完全和httplib解耦
~~~~~~~~
- 封装类为header-only, 直接inlude使用(封装的具体代码在文章最后的HttpServer.h中)
~~~~~~~~
- 避免了httplib原生使用方式阻塞主线程的问题
~~~~~~~~
- 在支持原生开发方式的基础上, 增加了BashController类, 以支持更常用的面向对象开发方式, 可以解耦代码, 支持较大型的web项目
~~~~~~~~
- 正文主要讲述使用方式, 封装的具体代码在文章最后, 可以直接复制使用
~~~~~~~~
- 跨平台, 可在linux和window中使用, 原生httplib对mingw支持不太好, mingw编译时需要添加ws2_32.lib
~~~~~~~~
- 关于httplib更高级的用法, 请直接到(cpp-httplib的github地址)参考
~~~~~~~~
- 确保你的编译器最低支持c++14
原生的httplib会阻塞你的主线程
~~~~~~~~ cpp-httplib是一个简单易用, 跨平台, 开发快速, 仅头文件的c++ http库. 只需要把一个头文件包含到你的代码里, 就可以用很少的代码完成一个http server, 就像下面这样. 但是, 它会阻塞当前线程, 导致while循环中的cout不执行, 看下面的代码
#include <httplib.h>
#include <chrono>
using namespace httplib;
using namespace std;
int main()
{
httplib::Server svr;
svr.Get("/hi", [](const httplib::Request &, httplib::Response &res)
{
res.set_content("Hello World!", "text/plain");
});
cout << "start http server" << endl;
// listen函数后, 将阻塞当前线程
svr.listen("0.0.0.0", 8080);
// 由于主线程被阻塞, 因此下面的代码不会执行
while (true)
{
cout << "main thread running ..." << endl;
this_thread::sleep_for(chrono::seconds(2)); // 睡眠2秒
}
return 0;
}
执行结果
~~~~~~~~ 阻塞的原因是因为, 在httplib的listen函数中有一个while循环, 其中不停的执行accept()函数, 用来监听端口对应的文件描述符, 所以, 只要你开一个子线程, 让listen函数在子线程中执行, 就不会阻塞主线程了
~~~~~~~~ 但其实你不用太关心原因, 甚至不用操心线程, 因为这些我都给你封装好了 _
解决httplib阻塞主线程的问题
~~~~~~~~ 把HttpServer.h复制到httplib的同级目录下, 在你的程序中include它, 通过HttpServer.h使用httplib, 就不会阻塞你的主线程了 , 如下:(HttpServer.h代码较多, 放到文章最后了)
~~~~~~~~ HttpServer.h的代码在文章的最后, 你可以直接复制使用
#include <httplib.h>
#include <chrono>
#include <HttpServer.h> // HttpServer.h头文件管理httplib::Server对象
using namespace httplib;
using namespace std;
int main()
{
// 实例化一个HttpServer对象hs, 内部会自动初始化httplib::Server
HttpServer* hs = new HttpServer("0.0.0.0", 8080);
// 获取hs内部的httplib::Server指针
Server* svr = hs->getHttplibServer();
// 使用httplib写服务器
svr->Get("/hi", [](const httplib::Request &, httplib::Response &res)
{
res.set_content("Hello World!", "text/plain");
});
cout << "start http server" << endl;
// HttpServer对象调用listenInThread(), 把listen函数放入一个子线程运行
// 注意, 子线程运行后不能让main函数退出, 因为主线程被关闭后, 所有的子线程会被强制关闭
hs->listenInThread();
while (true)
{
cout << "main thread running ..." << endl;
this_thread::sleep_for(chrono::seconds(2));
}
return 0;
}
执行结果
BashController - 面向对象风格使用httplib
~~~~~~~
- HttpServer.h不但能自动为你的httplib::Server对象创建子线程, 还提供了一种面向对象风格的http服务器开发方式, 以解耦你的代码. 让你的程序更加清晰明了.
~~~~~~~
- 你只需要继承BashController, 并按下面的方式编写的你服务器响应代码.
自定义controller — TestController.h文件
自定义controler, 解耦代码
#pragma once
#include "Httpserver.h"
class TestController : public httplib::BaseController
{
/*
private:
std::string* outsideObj;
public:
// 如果你要操作外部对象, 像下面一样写带参构造, 外部对象的指针传进来, 保存到成员变量, 就可以在响应函数里面用了
TestController(std::string* obj)
{
outsideObj = obj;
}
*/
private:
// 注意: 必须重写bind()函数, 并在内部填写映射关系, 否则会抛出一个runtime异常
void bind() override
{
// BindController可以绑定httplib中所有参数为(const httplib::Request& req, httplib::Response& resp)的方法
server->Get("/get", BindController(&TestController::getApi, this));
server->Post("/post", BindController(&TestController::postApi, this));
}
// 注意:Request和Response这两个参数必须是引用类型
void getApi(const httplib::Request& req, httplib::Response& resp)
{
std::string jsonData = "{\"type\": \"get\", \"code\": 2001}";
resp.set_content(jsonData, "application/json");
}
// 注意:Request和Response这两个参数必须是引用类型
void postApi(const httplib::Request& req, httplib::Response& resp)
{
std::string data = req.body;
std::cout << "接收请求数据: \n" << data << std::endl;
std::string jsonData = "{\"type\": \"post\", \"code\": 2001}";
resp.set_content(jsonData, "application/json");
}
};
使用controller功能的main.cpp文件
当你把自定义的controllor写到头文件中, 只在main中include它们时, 你的main函数会非常简洁和清晰, 像下面这样:
#include <HttpServer.h>
#include <chrono>
using namespace httplib;
using namespace std;
#include <TestController.h> // include你自定义的controllor
int main()
{
HttpServer* hs = new HttpServer("0.0.0.0", 8080);
// http服务运行期间, 要确保testController不被释放, 因此要用new创建testController
// hs释放时, 会自动释放你new出来的testController
hs->addController(new TestController()); // 初始化TestController对象, 并注入到hs
hs->listenInThread(); // 在子线程中启动http server
// hs->listenInLocal(); // 在当前线程中启动http server
while (true)
{
cout << "main thread running ..." << endl;
this_thread::sleep_for(chrono::seconds(2));
}
// 释放资源
delete hs;
}
get请求测试结果
post请求测试结果
附: AutoBashController - 宏绑定请求地址
~~~~~~~~ 如果你觉得重写Bind函数来绑定请求路径的方式过于繁琐, 那么你可以继承AutoBashController类, 通过一些特定的宏可以更方便地绑定请求函数
~~~~~~~~ AutoBashController和BashController功能完全一致, 区别是上一章的BashController在函数里面绑定请求地址, 而AutoBashController使用宏绑定请求地址
AutoContrloller.h文件 - 使用宏绑定的自定义controller
~~~~~~~~ 继承AutoBashController类, 以使用宏绑定功能
~~~~~~~~ 使用AutoBashController前, 先到httpserver.h文件中, 将里面的宏 HTTPSERVER_AUTO_CONTROLLER 的值改为1 (默认0)
#pragma once
#include "HttpServer.h"
/**
注意:
使用AutoBashController前, 先到httpserver.h文件中, 将里面的宏HTTPSERVER_AUTO_CONTROLLER 的值改为1 (默认0).
如果你的编译器无法编译, 那就把它关掉, 只使用BashController吧, AutoBashController只是更方便一点, 功能并无不同
说明:
宏绑定的功能只能在AutoBashController的子类中使用, BashController的子类中无法通过宏绑定请求地址
*/
#if HTTPSERVER_AUTO_CONTROLLER
class AutoController : public httplib::AutoBashController {
// 请求地址: http://127.0.0.1:8080/auto/get
GetRequestBind(getApi, "/auto/get"); // 使用宏绑定get请求,注意后面必须加分号, 下同
void getApi(const httplib::Request& req, httplib::Response& resp)
{
std::cout << "AutoController getApi code run " << std::endl;
resp.body = "{\"type\": \"auto_get\", \"code\": 2001}";
}
// 请求地址: http://127.0.0.1:8080/auto/post
PostRequestBind(postApi, "/auto/post"); // 使用宏绑定post请求
void postApi(const httplib::Request& req, httplib::Response& resp)
{
std::cout << "AutoController postApi code run " << std::endl;
resp.body = "{\"type\": \"auto_post\", \"code\": 2001}";
}
/*
BeforeFilter(beforeFunc);
void beforeFunc(const httplib::Request& req, httplib::Response& resp)
{
// 对所有使用宏绑定的请求生效
// 只对本类中的请求生效
std::cout << "--------- new requset ----------" << std::endl;
std::string info = req.body;
replace_all(info, "\r", "");
replace_all(info, "\n", "");
replace_all(info, " ", "");
std::string method = req.method;
std::string reqPath = req.path;
std::cout << "-- requset method = " << method << ", requset path = " << reqPath << ", request body = " <<
info
<< std::endl;
}
AfterFilter(afterFunc);
void afterFunc(const httplib::Request& req, httplib::Response& resp)
{
std::cout << "-- reqponse = " << resp.body << std::endl;
// 未设置响应格式时, 自动设置为json格式
if (!resp.has_header("Content-Type"))
{
resp.set_content(resp.body, "application/json");
}
}
*/
};
#endif
所有的请求绑定宏:
GetRequestBind(func, url)
PostRequestBind(func, url)
PutRequestBind(func, url)
PatchRequestBind(func, url)
DeleteRequestBind(func, url)
OptionRequestBind(func, url)
main.cpp文件添加controller
使用宏绑定方式的controller, 添加到server的方式和普通controller的添加方式一模一样
#include <HttpServer.h>
#include <chrono>
using namespace httplib;
using namespace std;
#include <TestController.h> // include你自定义的controllor, 函数绑定
#include <AutoController.h> // include你自定义的controllor, 宏绑定
/**
TestController请求地址:
http://127.0.0.1:8080/get
http://127.0.0.1:8080/post
AutoController请求地址:
http://127.0.0.1:8080/auto/get
http://127.0.0.1:8080/auto/post
*/
int main()
{
HttpServer* hs = new httplib::HttpServer(8080);
hs->addController(new TestController()); // 函数绑定; hs释放时, 会自动释放你new出来的controller
#if HTTPSERVER_AUTO_CONTROLLER // 先到HttpServer.h文件中, 把宏 HTTPSERVER_AUTO_CONTROLLER 的值改为1
hs->addController(new AutoController()); // 宏绑定
#endif
hs->listenInThread(); // 线程中监听
while (true)
{
// std::cout << "main thread running" << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(2));
}
return 0;
}
HttpServer.h
将该文件放在httplib的同级目录下, 就能按照文章中提到的方式使用它们了
// 将HttpServer.h放到httplib.h文件的同级目录下, 就能按照文章中提到的方式使用它们了
#pragma once
#include "httplib.h"
#include <functional>
#include <iostream>
#include <string>
#include <typeinfo>
#include <unordered_map>
#include <vector>
/**
* @brief 该宏为1时, 打开AutoBashController的代码. 为0时, 关闭AutoBashController的代码
*
* 如果编译不过去或绑定失败, 将该值改为0. 请只使用BashController(AutoBashController只是更方便一点, 功能并无不同)
*/
#define HTTPSERVER_AUTO_CONTROLLER 1
namespace httplib {
// 线程池(复制的httplib的线程池, 添加了动态增加线程数量的功能)
class MyHttpServerThreadPool {
public:
explicit MyHttpServerThreadPool(size_t n);
void addAThread();
std::size_t getThreadNum();
MyHttpServerThreadPool(const ThreadPool&) = delete;
~MyHttpServerThreadPool();
void enqueue(std::function<void()> fn);
void shutdown();
private:
struct worker {
explicit worker(MyHttpServerThreadPool& pool) : pool_(pool) {}
void operator()();
MyHttpServerThreadPool& pool_;
};
friend struct worker;
std::vector<std::thread> threads_;
std::list<std::function<void()>> jobs_;
bool shutdown_;
std::condition_variable cond_;
std::mutex mutex_;
};
class BaseController;
#if HTTPSERVER_AUTO_CONTROLLER
class AutoBashController;
#endif
// HttpServer, 用于管理httplib::Server对象
class HttpServer {
private:
std::string host = "";
int port = -1;
inline static httplib::MyHttpServerThreadPool* serverPool = nullptr;
httplib::Server* server = new httplib::Server();
inline static std::atomic<int> poolUseNum = 0;
int socket_flags;
void buildServerThreadPool();
friend class BaseController;
std::vector<BaseController*> controllerVec;
httplib::Server::Handler default_error_handler = [](const httplib::Request& req, httplib::Response& resp) {
std::string error_code = std::to_string(resp.status);
resp.set_content(error_code, "text/plain");
};
#if HTTPSERVER_AUTO_CONTROLLER
friend class AutoBashController;
std::vector<AutoBashController*> autoControllerVec;
#endif
public:
HttpServer(const HttpServer&) = delete;
HttpServer() = delete;
HttpServer(const std::string& _host, int _port, int _socket_flags = 0);
HttpServer(int _port, int _socket_flags = 0);
void addController(httplib::BaseController* controller);
#if HTTPSERVER_AUTO_CONTROLLER
void addController(httplib::AutoBashController* controller);
#endif
httplib::Server* getHttplibServer();
/*
如果serverPool为null, 将为static serverPool 创建一个新的HttpThreadPool, 并在该线程池中监听
如果serverPool不为null, 将直接使用static serverPool, 在线程池中执行httplib::Server的listen函数
*/
void listenInThread();
// 在本地监听httplib::Server的listen函数
void listenInLocal();
// 释放server指针,如果poolUseNum为0, 也将释放serverPool
~HttpServer();
};
// BashController, 模仿java spring mvc的开发风格
class BaseController {
public:
BaseController() = default;
BaseController(BaseController&) = delete;
~BaseController();
protected:
// 必须重写bind方法, 在其中绑定具体的请求响应地址和请求响应方法, 否则抛出一个string异常
virtual void bind();
httplib::Server* server = nullptr;
friend class httplib::HttpServer;
// 绑定函数
template <class Func, class T>
auto BindController(Func&& func, T&& obj)
{
httplib::Server::Handler handler = std::bind(func, obj, std::placeholders::_1, std::placeholders::_2);
return handler;
}
void replace_all(std::string& str, const std::string& old_value, const std::string& new_value);
private:
void initToServer(httplib::Server* _server);
void initToServer(httplib::HttpServer* _server);
};
} // namespace httplib
#if HTTPSERVER_AUTO_CONTROLLER
namespace httplib {
enum class HttpServerRequestType { GET, POST, PUT, PATCH, DEL, Options };
enum class HttpServerFilterType { REQUEST_FILTER, RESPONCE_FILTER };
class AutoBashController {
friend httplib::HttpServer;
inline static std::unordered_map<std::string, std::pair<HttpServerRequestType, httplib::Server::Handler>>
__autoBindFuncMap{};
inline static std::mutex __autoMapResetMtx;
public:
void replace_all(std::string& str, const std::string& old_value, const std::string& new_value);
protected:
// 当这个结构体初始化时, 会把绑定函数放到map里面
struct PathStruct__;
struct FilterStruct__;
httplib::Server::Handler __request_filter = nullptr;
httplib::Server::Handler __response_filter = nullptr;
private:
httplib::Server* __httplib_server;
virtual void bind();
void initToServer(httplib::Server* _server);
void initToServer(httplib::HttpServer* _server);
};
} // namespace httplib
#endif
/* ============================================================== */
/* ============================================================== */
/* =========================== 源文件 ============================ */
/* ============================================================== */
/* ============================================================== */
// #include "HttpServer.h"
inline httplib::MyHttpServerThreadPool::MyHttpServerThreadPool(size_t n) : shutdown_(false)
{
while (n)
{
std::thread task(worker(*this));
task.detach();
threads_.emplace_back(std::move(task));
n--;
}
}
inline void httplib::MyHttpServerThreadPool::addAThread()
{
std::thread task(worker(*this));
task.detach();
threads_.emplace_back(std::move(task));
}
inline std::size_t httplib::MyHttpServerThreadPool::getThreadNum()
{
return threads_.size();
}
inline httplib::MyHttpServerThreadPool::~MyHttpServerThreadPool()
{
shutdown();
}
inline void httplib::MyHttpServerThreadPool::enqueue(std::function<void()> fn)
{
{
std::unique_lock<std::mutex> lock(mutex_);
jobs_.push_back(std::move(fn));
}
cond_.notify_one();
}
inline void httplib::MyHttpServerThreadPool::shutdown()
{
// Stop all worker threads...
{
std::unique_lock<std::mutex> lock(mutex_);
shutdown_ = true;
}
// 停止任务添加器
cond_.notify_all();
}
inline void httplib::MyHttpServerThreadPool::worker::operator()()
{
for (;;)
{
std::function<void()> fn;
{
std::unique_lock<std::mutex> lock(pool_.mutex_);
pool_.cond_.wait(lock, [&] {
return !pool_.jobs_.empty() || pool_.shutdown_;
});
if (pool_.shutdown_ && pool_.jobs_.empty())
{
break;
}
fn = std::move(pool_.jobs_.front());
pool_.jobs_.pop_front();
}
assert(true == static_cast<bool>(fn));
fn();
}
}
inline httplib::HttpServer::HttpServer(const std::string& _host, int _port, int _socket_flags)
: host(std::move(_host)), port(_port), socket_flags(_socket_flags)
{
server->set_error_handler(this->default_error_handler);
}
inline httplib::HttpServer::HttpServer(int _port, int _socket_flags)
: host(std::move("0.0.0.0")), port(_port), socket_flags(_socket_flags)
{
server->set_error_handler(this->default_error_handler);
}
inline void httplib::HttpServer::buildServerThreadPool()
{
poolUseNum++;
if (serverPool == nullptr)
{
// 创建了一个空线程池, 里面没有线程
serverPool = new httplib::MyHttpServerThreadPool{0};
}
}
inline void httplib::HttpServer::addController(httplib::BaseController* controller)
{
controllerVec.push_back(controller);
controller->initToServer(this);
}
inline httplib::Server* httplib::HttpServer::getHttplibServer()
{
return server;
}
inline void httplib::HttpServer::listenInThread()
{
buildServerThreadPool();
if (serverPool != nullptr)
{
serverPool->addAThread();
std::cout << "listen to " << port << std::endl;
serverPool->enqueue(std::move(std::bind(&httplib::Server::listen, server, host, port, socket_flags)));
return;
}
std::cout << __func__ << " failed, httplib::HttpServer: threadpool is nullptr" << std::endl;
}
inline void httplib::HttpServer::listenInLocal()
{
bool ret = server->listen(host, port, socket_flags);
}
inline httplib::HttpServer::~HttpServer()
{
poolUseNum--;
if (this->server != nullptr)
{
server->stop();
delete server;
}
if (poolUseNum == 0 && serverPool != nullptr)
{
delete serverPool;
serverPool = nullptr;
}
if (controllerVec.size() > 0)
{
for (auto it = controllerVec.begin(); it != controllerVec.end();)
{
BaseController* baseController = *it;
if (baseController != nullptr)
{
delete (baseController);
controllerVec.erase(it);
}
else
{
it++;
}
}
}
#if HTTPSERVER_AUTO_CONTROLLER
if (autoControllerVec.size() > 0)
{
for (auto it = autoControllerVec.begin(); it != autoControllerVec.end();)
{
AutoBashController* autoController = *it;
if (autoController != nullptr)
{
delete (autoController);
autoControllerVec.erase(it);
}
else
{
it++;
}
}
}
#endif
}
inline void httplib::BaseController::replace_all(std::string& str, const std::string& old_value,
const std::string& new_value)
{
std::string::size_type pos(0);
while ((pos = str.find(old_value)) != std::string::npos)
{
str.replace(pos, old_value.length(), new_value);
}
}
inline void httplib::BaseController::initToServer(httplib::Server* _server)
{
server = _server;
// print("{} init to server", typeid(*this).name());
this->bind();
}
inline void httplib::BaseController::initToServer(httplib::HttpServer* _server)
{
server = _server->getHttplibServer();
// print("{} init to server", typeid(*this).name());
this->bind();
}
inline void httplib::BaseController::bind()
{
throw std::runtime_error(std::string("HttpServer must override ") + __FUNCTION__);
}
inline httplib::BaseController::~BaseController()
{
if (server != nullptr)
{
server = nullptr;
}
// print("destroy controller");
}
#if HTTPSERVER_AUTO_CONTROLLER
inline void httplib::HttpServer::addController(httplib::AutoBashController* controller)
{
autoControllerVec.push_back(controller);
controller->initToServer(this);
}
inline void httplib::AutoBashController::bind()
{
if (httplib::AutoBashController::__autoBindFuncMap.size() == 0)
{
std::cout << "httplib::HttpServer[AutoBashController] warning: bind request path/func failed, map size = 0, "
"maybe you need use HttpServer.addController(your controller)\n";
}
std::unique_lock<std::mutex> ulock(__autoMapResetMtx);
for (auto& it : httplib::AutoBashController::__autoBindFuncMap)
{
HttpServerRequestType requestType = it.second.first;
std::function<void(const httplib::Request&, httplib::Response&)> func = it.second.second;
switch (requestType)
{
case httplib::HttpServerRequestType::GET: {
__httplib_server->Get(it.first, std::move(func));
break;
}
case httplib::HttpServerRequestType::POST: {
__httplib_server->Post(it.first, std::move(func));
break;
}
case httplib::HttpServerRequestType::PUT: {
__httplib_server->Put(it.first, std::move(func));
break;
}
case httplib::HttpServerRequestType::PATCH: {
__httplib_server->Patch(it.first, std::move(func));
break;
}
case httplib::HttpServerRequestType::DEL: {
__httplib_server->Delete(it.first, std::move(func));
break;
}
case httplib::HttpServerRequestType::Options: {
__httplib_server->Options(it.first, std::move(func));
break;
}
}
}
__autoBindFuncMap.clear();
}
inline void httplib::AutoBashController::replace_all(std::string& str, const std::string& old_value,
const std::string& new_value)
{
std::string::size_type pos(0);
while ((pos = str.find(old_value)) != std::string::npos)
{
str.replace(pos, old_value.length(), new_value);
}
}
struct httplib::AutoBashController::PathStruct__ {
PathStruct__(const HttpServerRequestType requestType, const std::string& path,
const httplib::Server::Handler& requestFunc)
{
if (path.find_first_of('/') != 0)
{
std::string warn_info =
std::string("httplib::HttpServer[AutoBashController] warning: error request path = ") + path +
", maybe /\"" + path + "\" is right";
std::cout << warn_info << std::endl;
}
httplib::AutoBashController::__autoBindFuncMap.emplace(path,
std::make_pair(requestType, std::move(requestFunc)));
}
};
struct httplib::AutoBashController::FilterStruct__ {
FilterStruct__(const HttpServerFilterType filterType, AutoBashController* controllerObj,
httplib::Server::Handler&& requestFunc)
{
if (filterType == httplib::HttpServerFilterType::REQUEST_FILTER)
{
controllerObj->__request_filter = std::move(requestFunc);
}
else if (filterType == httplib::HttpServerFilterType::RESPONCE_FILTER)
{
controllerObj->__response_filter = std::move(requestFunc);
}
}
};
inline void httplib::AutoBashController::initToServer(httplib::Server* _server)
{
__httplib_server = _server;
// print("{} init to server", typeid(*this).name());
this->bind();
}
inline void httplib::AutoBashController::initToServer(httplib::HttpServer* _server)
{
__httplib_server = _server->getHttplibServer();
// print("{} init to server", typeid(*this).name());
this->bind();
}
#endif
// 绑定宏
#if HTTPSERVER_AUTO_CONTROLLER
#define __HTTPLIB_CREATE_CONST_VAR_NAME(a, b) a##b
#define HTTPLIB_CREATE_CONST_VAR_NAME(a, b) __HTTPLIB_CREATE_CONST_VAR_NAME(a, b)
#define __RequestBind(requestType, requestFunc, url) \
const PathStruct__ HTTPLIB_CREATE_CONST_VAR_NAME(p, __LINE__) = { \
httplib::requestType, url, [&](const httplib::Request& req, httplib::Response& resp) { \
if (this->__request_filter != nullptr) \
this->__request_filter(req, resp); \
this->requestFunc(req, resp); \
if (this->__response_filter != nullptr) \
this->__response_filter(req, resp); \
}}
#define __FilterBind(filterType, filterFunc) \
const FilterStruct__ HTTPLIB_CREATE_CONST_VAR_NAME(p, __LINE__) = { \
httplib::filterType, this, [&](const httplib::Request& req, httplib::Response& resp) { \
this->filterFunc(req, resp); \
}}
#define GetRequestBind(requestFunc, url) __RequestBind(HttpServerRequestType::GET, requestFunc, url)
#define PostRequestBind(requestFunc, url) __RequestBind(HttpServerRequestType::POST, requestFunc, url)
#define PutRequestBind(requestFunc, url) __RequestBind(HttpServerRequestType::PUT, requestFunc, url)
#define PatchRequestBind(requestFunc, url) __RequestBind(HttpServerRequestType::PATCH, requestFunc, url)
#define DeleteRequestBind(requestFunc, url) __RequestBind(HttpServerRequestType::DEL, requestFunc, url)
#define OptionRequestBind(requestFunc, url) __RequestBind(HttpServerRequestType::Options, requestFunc, url)
#define BeforeFilter(filterFunc) __FilterBind(HttpServerFilterType::REQUEST_FILTER, filterFunc)
#define AfterFilter(filterFunc) __FilterBind(HttpServerFilterType::RESPONCE_FILTER, filterFunc)
#endif