cpp-httplib 避免阻塞主线程, c++封装httplib,httplib面向对象开发

说明/前言

         ~~~~~~~~          - 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原生使用方式的执行结果

         ~~~~~~~~         阻塞的原因是因为, 在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
评论 30
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值