httplib 库介绍与使用

说明:
cpp-httplib 是个开源的库,是一个c++封装的http库,使用这个库可以在linux、windows平台下完成http客户端、http服务端的搭建,这是一个多线程“阻塞”HTTP 库。
使用起来非常方便,只需要包含头文件httplib.h即可。
源码库地址:https://github.com/yhirose/cpp-httplib
 
httplib 库基本结构:
发送请求Request类的组成:
 
class Request
{
std::string method;  // 请求方法
std::string path; // 请求路径
map<std::string, std::string> param;  // 查询字符串(查询字符串中)
map<std::string, std::string> headers;// 键值对头部
std::string body; //正文
};
 
 
响应数据类Response的组成:
 
class Response
{
int status; //返回的状态码
map<std::string,std::string> headers; //返回的价值对头部
std::string body; //正文
};
 
 
服务端Server 类的组成:
 
class Server {
public:
  using Handler = std::function<void(const Request &, Response &)>;
  using HandlerWithContentReader = std::function<void(
      const Request &, Response &, const ContentReader &content_reader)>;
  using Expect100ContinueHandler =
      std::function<int(const Request &, Response &)>;
 
  Server();
 
  virtual ~Server();
 
  virtual bool is_valid() const;
 
  Server &Get(const char *pattern, Handler handler);
  Server &Post(const char *pattern, Handler handler);
  Server &Post(const char *pattern, HandlerWithContentReader handler);
  Server &Put(const char *pattern, Handler handler);
  Server &Put(const char *pattern, HandlerWithContentReader handler);
  Server &Patch(const char *pattern, Handler handler);
  Server &Patch(const char *pattern, HandlerWithContentReader handler);
  Server &Delete(const char *pattern, Handler handler);
  Server &Delete(const char *pattern, HandlerWithContentReader handler);
  Server &Options(const char *pattern, Handler handler);
 
 
客户端Client 类的组成:
 
class Client
{
//创建client
Client(host,port);
Get()
Post()
Put()
...
};
 
简单实例:
Server:
 
#define CPPHTTPLIB_OPENSSL_SUPPORT
#include "path/to/httplib.h"
// HTTP
httplib::Server svr;
// HTTPS
httplib::SSLServer svr;
svr.Get("/hi", [](const httplib::Request &, httplib::Response &res) {
  res.set_content("Hello World!", "text/plain");
});
svr.listen("0.0.0.0", 8080);
 
Client:
 
#define CPPHTTPLIB_OPENSSL_SUPPORT
#include "path/to/httplib.h"
// HTTP
httplib::Client cli("http://cpp-httplib-server.yhirose.repl.co");
// HTTPS
httplib::Client cli("https://cpp-httplib-server.yhirose.repl.co");
auto res = cli.Get("/hi");
res->status;
res->body;
 
SSL Support:
 
SSL support 要用到 CPPHTTPLIB_OPENSSL_SUPPORT. libssl and libcrypto 的支持。
现在只有 httplib 1.1.1 支持ssl 服务器。
 
#define CPPHTTPLIB_OPENSSL_SUPPORT
#include "path/to/httplib.h"
// Server
httplib::SSLServer svr("./cert.pem", "./key.pem");
// Client
httplib::Client cli("https://localhost:1234"); // scheme + host
httplib::SSLClient cli("localhost:1234"); // host
// Use your CA bundle
cli.set_ca_cert_path("./ca-bundle.crt");
// Disable cert verification
cli.enable_server_certificate_verification(false);
 
g++ -o service service.cpp -I/usr/local/openssl/include -L/usr/local/openssl/lib -lssl -lcrypto -pthread
 
完整简单web例子:
#include <stdio.h>
#include <iostream>
 
#include <jsoncpp/json/json.h>
#include "httplib.h"
 
using namespace httplib;
using namespace std;
 
int g_val = 100;
void Get_CallBackFunc(const Request& req, Response& resp)
{
    printf("%d\n", g_val);
    cout << req.method << endl; 
    printf("i am Get_CallBackFunc\n");
 
    const char* lp = "<html><h2>hello bite!</h2></html>";
    resp.set_content(lp, strlen(lp), "text/html");
}
 
int main()
{
    Server http_svr;
    int a = 10;
    http_svr.Get("/abc", Get_CallBackFunc);
    http_svr.Post("/login", [](const Request& req, Response& resp){
            cout << req.body << endl;
 
            Json::Value resp_json;
            resp_json["login_status"] = true;
            Json::FastWriter w;
            resp.body = w.write(resp_json);
 
            resp.set_header("Content-Type", "application/json");
            });
    http_svr.set_mount_point("/", "./web");
    http_svr.listen("0.0.0.0", 21010);
    return 0;
}
 
 
完整简单upload例子:
#include "httplib.h"
#include <iostream>
#include <fstream>
 
using namespace httplib;
using namespace std;
 
int main(void)
{
    Server svr;
    svr.Post("/post", [](const Request &req, Response &res) {
        auto music_file = req.get_file_value("music_file");
 
        cout << "image file length: " << music_file.content.length() << endl
             << "image file name: " << music_file.filename << endl;
        {
            ofstream ofs(music_file.filename, ios::binary);
            ofs << music_file.content;
        }
        res.set_content("done", "text/plain");
    });
    svr.set_mount_point("/", "./www");
    /// listen
    svr.listen("0.0.0.0", 9089);
}
 
 
 
 

编译brotli源码

 

1.1. 下载安装

下载 libbrotli, brotli

如果虚拟机可以上网,clone libbrotli 之后,就可以使用 autogen.sh 直接编译

git clone https://github.com/bagder/libbrotli
cd libbrotli
./autogen.sh && ./configure && make && make install

如果虚拟机不能上网,可以将 brotli 也下载好之后,直接放在 libbrotli 的目录之下,目录结构:libbrotli/brotli/c

git clone https://github.com/bagder/libbrotli
git clone https://github.com/google/brotli.git

cd libbrotli
# ll brotli/c
./autogen.sh && ./configure && make && make install

1.1.1. 编译问题解决

  1. Makefile.am: C objects in subdir but AM_PROG_CC_C_O' not inconfigure.ac'
  2. Libtool library used but `LIBTOOL' is undefined,我在centos6的环境下编译通过,在centos5的环境下没有编译通过(没有特别去搞el5的环境,猜测可能需要升级libtool)。

在configure.am中添加 AM_PROG_CC_C_O

AC_PROG_CC
AM_PROG_CC_C_O

1.2. 编译示例代码

上面的编译过程之后,会生成了对应的静态库和动态库,在 libbrotli 目录的 .libs 目录下。也可以直接使用过来作为库的方式加载。(后续准备写一个简单的测试例子来验证)

gcc -g -o brotli brotli.c -I. -I. -I..  -I../brotli/c/include ../.libs/libbrotlienc.so ../.libs/libbrotlidec.so -lm
gcc -g -o brotli brotli.c -I. -I. -I..  -I../brotli/c/include libbrotlienc.a libbrotlidec.a -lm

1.3. 应用实例

# 压缩:压缩等级从0-11
time brotli -q 0 /www/docs/100M.file -o 100M.file.C

real    0m0.344s
user    0m0.271s
sys 0m0.072s

# 解压
time brotli -d 100M.file.C -o 100M.file
real    0m0.552s
user    0m0.392s
sys 0m0.159s

# 最终处理结果
ll 100M.file* -h
-rw-r--r-- 1 root root 100M Nov  6  2018 100M.file
-rw-r--r-- 1 root root  89K Nov  6  2018 100M.file.C

1.4. 使用源码生成动静态库

./autogen.sh && ./configure --prefix=/home/xxx/brotli/libbrotli-master/target && make && make install

ll target/lib/*
-rw-r--r-- 1 root root  487628 Aug 16 11:19 target/lib/libbrotlidec.a
-rw-r--r-- 1 root root 3466066 Aug 16 11:19 target/lib/libbrotlienc.a

ls target/include/brotli/
decode.h  encode.h  port.h  types.h

将静态库和include里面的.h文件拷贝出来,就可以用来编译自己的程序了,也可以移植到自己的程序中,比如网上资料最多的 nginx。 我工作用的是squid,也是通过这种方式支持的

gcc -g -o test_brotli test_brotli.c -I../target/brotli/include ../target/lib/libbrotlienc.a -lm

# test_brotli.c, 程序设计其实有问题,不过这里贴出来只是作为给大家编译用的测试demo
#include "brotli/encode.h"
#include "brotli/decode.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int
test_brotli_compress()
{
    int is_ok = 1;
    BrotliEncoderState* s = BrotliEncoderCreateInstance(NULL, NULL, NULL);
    if (!s) {
        fprintf(stderr, "out of memory\n");
        return 0;
    }

    int quality = 1;
    int lgwin = 22;
    BrotliEncoderSetParameter(s, BROTLI_PARAM_QUALITY, quality);
    BrotliEncoderSetParameter(s, BROTLI_PARAM_LGWIN, lgwin);
    uint8_t* input_buf = (uint8_t*)malloc(1024);
    uint8_t* out_buf = (uint8_t*)malloc(4096);

    size_t available_in = 0;        /* length of real data */
    size_t available_out = 1024;    /* length of buf befor call compress, and length of remain size of buf after compress */
    const uint8_t* next_in = NULL;  /* start of in buff */
    uint8_t* next_out = NULL;       /* start of out buff */
    strcpy((char *)input_buf, "abcdefghijklmnopqrstuvwxyz");

    next_in = input_buf;    /* actually data must be binary data */
    available_in = strlen("abcdefghijklmnopqrstuvwxyz");
    available_out = 1024;
    next_out = out_buf;
    if (!BrotliEncoderCompressStream(s, BROTLI_OPERATION_PROCESS, &available_in, &next_in, &available_out, &next_out, NULL)) {
        /* Should detect OOM? */
        fprintf(stderr, "failed to compress data [%s]\n", "abcdefghijklmnopqrstuvwxyz");
        is_ok = 0;
        goto failed;
    }

    next_in = NULL;
    available_in = 0;
    if (available_out != 1024) {
        next_out = out_buf + (1024 - available_out); /* buf + out_size */
        available_out = 1024;
    }
    if (!BrotliEncoderCompressStream(s, BROTLI_OPERATION_FINISH, &available_in, &next_in, &available_out, &next_out, NULL)) {
        /* Should detect OOM? */
        fprintf(stderr, "failed to compress data [%s]\n", "0123456789");
        is_ok = 0;
        goto failed;
    }

    if (BrotliEncoderIsFinished(s)) is_ok = 1;
    BrotliEncoderDestroyInstance(s);

failed:
    free(input_buf);
    free(input_buf2);
    free(out_buf);
    return is_ok;
}

int main()
{
    test_brotli_compress();
    return 0;
}

1.5. 写在最后

如果大家觉有用,可以留言。后续可能会再补充在支持过程中遇到的其他问题
更新时间: 2019.08.16



 
 
posted @ 2023-07-14 11:54  阿风小子  阅读(4658)  评论(1编辑  收藏  举报