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库的使用(支持http/https)(一)_第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 
#include 

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类对象实例,其定义为
httplib库的使用(支持http/https)(一)_第2张图片
我们一般主要引用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.其他资料

第二篇:
httlib库的使用(文件分块传输chunked data)(二)

此外还有几篇针对httplib库写的不错的文章,一并收藏在此:
C++ httplib 解读
cpp-httplib库的原理
C++ Http/Https服务器和客户端库cpp-httplib

你可能感兴趣的:(httplib库的使用,c++,http,https)