httplib库的使用(支持http/https)

httplib库的使用,支持http/https
httplib库简介
1. 文件目录
2. client端
2.1 快速搭建一个client端
2.2 HTTPS
2.3 下载文件
2.4 GET大数据
2.5 POST大数据
2.6 上传文件
3. server端的简单使用
4.其他资料
httplib库简介
httplib库是一个以C++11特性编写的库,所以编译器也需要能支持C++11的。库在使用时只需包含一个头文件即可,非常方便。
 
下载地址
 
注意:此库为线程阻塞,使用时还请注意。
 
1. 文件目录
下载后的包解压后有如下文件
其中httplib.h为库的头文件,使用时只需要将此头文件包含在你的代码中即可。
 
example:此文件夹中有作者分享的一些代码示例,使用时可参考。
 
split.py:此文件为python执行文件,如果你还是想用.h和.cpp的方式将库加入到你的工程中,可以运行此文件。执行成功后会在同目录下生成一个out文件夹,里面便包含了分离的.cc和.h文件。
 
2. client端
2.1 快速搭建一个client端
使用时需先引入命名空间using namespace httplib,当然也可以在调用相关类时直接加上httplib::域。
 
如下直接建立一个http的client端,连接到本地 1234端口,获取链接 /hi下的数据,数据的主体都在返回的res->body中。
 
#include <httplib.h>
#include <iostream>
 
int main(void)
{
  httplib::Client cli("localhost", 1234);
 
  if (auto res = cli.Get("/hi")) {
    if (res->status == 200) {
      std::cout << res->body << std::endl;
    }
  } else {
    auto err = res.error();
    ...
  }
}
 
 
res是Response类对象实例,其定义为
我们一般主要引用body,这里面就是数据。头字段的话则包含在header中。
 
链接的错误信息返回在res.error中,error定义为
 
enum Error {
  Success = 0,
  Unknown,
  Connection,
  BindIPAddress,
  Read,
  Write,
  ExceedRedirectCount,
  Canceled,
  SSLConnection,
  SSLLoadingCerts,
  SSLServerVerification,
  UnsupportedMultipartBoundaryChars
};
 
链接成功后,通过Get的url返回的状态码在res->status中,此状态码即为HTTP状态码。
 
2.2 HTTPS
库默认使用的是HTTP,如果要使用HTTPS,需在程序中定义
 
#define CPPHTTPLIB_OPENSSL_SUPPORT
 
使用时可参考
 
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
        httplib::SSLClient client(ser_ip, ser_port); //https
        client.enable_server_certificate_verification(true); //看实际情况使能
        client.set_ca_cert_path("ca-bundle.crt"); //设置ca证书
#else
        httplib::Client client("127.0.0.1:80"); //http
#endif
 
另外注意:使用HTTPS方式时,需引入ssl库,且当前库只支持ssl version 1.1.1版本。
 
2.3 下载文件
下载可以使用GET方法,并且可以通过以下代码获取下载文件的进度(代码将获取到的数据保存为down_file.tar格式的文件,因为传递过程中是以二进制数据传递,文件类型可以根据实际情况保存,此只是做个示例):
 
if(auto res = client.Get("/hi", [](uint64_t len, uint64_t total) {
     printf("%lld / %lld bytes => %d%% complete\n",len, total,(int)(len*100/total));
     return true; // return 'false' if you want to cancel the request.
}))
{
printf("status:%d\n",res->status);
    if(res->status == 200)
    {
        std::ofstream out;
        out.open("down_file.tar", std::ios_base::binary | std::ios::out);
        printf("savefile!\n");
        if(out.is_open())
        {
            out<<res->body;
            out.close();
            printf("down load file finished!\n");
        }
        else
        {
            printf("open file error!\n");
        }
    }
}
else
{
    printf("url connect failed! error = %d\n",(int)res.error());
}
 
 
2.4 GET大数据
如果GET数据太大,可使用如下的方式接收:
 
std::string body;
 
auto res = cli.Get("/large-data",
  [&](const char *data, size_t data_length) {
    body.append(data, data_length);
    return true;
  });
 
2.5 POST大数据
笔者在使用过程中将一个200M以上的文件读取后POST会报段错误,原因是读取文件后POST过程中会有拷贝过程,文件或者数据量太大时会有问题。可使用如下方法POST:
 
std::string body = ...;
 
auto res = cli.Post(
  "/stream", body.size(),
  [&](size_t offset, size_t length, DataSink &sink) {
    sink.write(body.data() + offset, length);
    return true; // return 'false' if you want to cancel the request.
  },
  "text/plain");
 
2.6 上传文件
上传文件需使用MultipartFormData,笔者在使用过程中发现,利用此方法上传文件有限制,文件太大时会报段错误(笔者测试时使用的是200多M的文件,具体临界值没有测试)。所以建议在读取文件时加上文件大小限制的判断。
 
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
        httplib::SSLClient client(ser_ip, ser_port);
        client.enable_server_certificate_verification(true); //看实际情况使能
        client.set_ca_cert_path("ca-bundle.crt");
#else
        httplib::Client client("127.0.0.1:80");
#endif
 
        std::string body = "";
        //此处添加读取上传文件的代码,将读取到的数据存入body中
        
        httplib::MultipartFormData updataData;
        updataData.name = "upfile";
        updataData.content = body;
        updataData.filename = file_name;
        updataData.content_type = content_type;
        httplib::MultipartFormDataItems items;
        items.push_back(updataData);
        if (auto res = client.Post(file_upload_url.c_str(), items))
        {
            if (res->status != 200)
            {
                printf("error status = %d\n",res->status);
                return -4;
            }
            else
            {
                return 0; //upload file success
            }
        }
        else
        {
            printf("url connect failed! error = %d\n",(int)res.error());
            return -5;
        }
    }
    else
    {
        printf("read upload file error\n");
        return -3;
    } 
 
 
3. server端的简单使用
服务端程序可参考如下代码,程序线程会阻塞在listen处,因此建议另开一个线程来监听。
 
#define SERVER_CERT_FILE "./cert.pem"
#define SERVER_PRIVATE_KEY_FILE "./key.pem"
 
int main(void) {
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
  SSLServer svr(SERVER_CERT_FILE, SERVER_PRIVATE_KEY_FILE);
#else
  Server svr;
#endif
 
  if (!svr.is_valid()) {
    printf("server has an error...\n");
    return -1;
  }
 
  svr.Get("/hi", [](const Request& req, Response& res) {
    res.set_content("Hello World!", "text/plain");
  });
 
  svr.Get(R"(/numbers/(\d+))", [&](const Request& req, Response& res) {
    auto numbers = req.matches[1];
    res.set_content(numbers, "text/plain");
  });
 
  svr.Get("/body-header-param", [](const Request& req, Response& res) {
    if (req.has_header("Content-Length")) {
      auto val = req.get_header_value("Content-Length");
    }
    if (req.has_param("key")) {
      auto val = req.get_param_value("key");
    }
    res.set_content(req.body, "text/plain");
  });
 
  svr.Get("/stop", [&](const Request& req, Response& res) {
    svr.stop();
  });
 
  svr.listen("localhost", 1234);
 
  return 0;
}
 
 
4.其他资料
此外还有几篇针对httplib库写的不错的文章,一并收藏在此:
C++ httplib 解读
cpp-httplib库的原理
C++ Http/Https服务器和客户端库cpp-httplib
 
posted @ 2023-07-14 16:16  阿风小子  阅读(4070)  评论(0编辑  收藏  举报