Bootstrap

C++第三方库 【HTTP/HTTPS】— httplib库

目录

认识httplib库

安装httplib库

httplib的使用

 httplib请求类

 httplib响应类

Server类

Client类

httplib库搭建简单服务器&客户端


认识httplib库

httplib库,是一个C++11单头文件的,轻量级的跨平台HTTP/HTTPS库,可以用来创建简单的HTTP服务器和客户端。其被设计成简单易用,适用于快速开发和测试,而不需要深入了解底层的HTTP协议。免去搭建服务器或客户端的时间,更快设计具体的业务处理,提高开发效率。

安装httplib库

GitHub链接

在Linux命令行输入如下命令,安装rz

sudo yum install lrzsz 

 再使用unzip命令解压压缩包

若没有unzip命令,执行如下命令安装

sudo yum install unzip

httplib的使用

 httplib请求类

HTTP请求报文可以参看HTTP请求

httplib中封装了一个结构——Request,用来保存客户端/浏览器发送的HTTP请求的内容。当服务器获取到客户端的请求,httplib会将请求字符串解析成Request

struct Request {
        //成员变量
        std::string method;//请求方法
        std::string path;//请求资源路径——URL
        Headers headers;//头部字段
        std::string body;//正文部分
        std::string version;//协议版本
        Params params;//查询字符串
        MultipartFormDataMap files;//客户端上传文件的信息
        Ranges ranges;//实现断点续传的请求区间
        //提供的API
        //查询头部字段key是否存在
        bool has_header(const char *key) const;
        //获取头部字段的value
        std::string get_header_value(const char *key, size_t id = 0) const;
        //设置头部字段
        void set_header(const char *key, const char *val);
        //查询客户端是否上传该文件
        bool has_file(const char *key) const;
        //获取文件信息
        MultipartFormData get_file_value(const char *key) const;
   };

其中有一个文件结构体和文件结构体数组

struct MultipartFormData {
        std::string name;//字段名称
        std::string content;//文件内容
        std::string filename;//文件名
        std::string content_type;//文件类型
};
//文件结构体数组
using MultipartFormDataItems = std::vector<MultipartFormData>;

 httplib响应类

HTTP响应报文可以参看HTTP响应

httplib响应类是Responce,需要用户手动填补,httplib返回响应时,会将Responce组织成字符串返回给客户端

struct Response {
    std::string version;   //协议版本号,默认时http1.1
    int status = -1;       //响应状态码,
    std::string reason;    
    Headers headers;       //响应报头
    std::string body;      //响应正文
    std::string location; // 重定向位置
//两个比较重要的API
//以key-val将相应的字段设定到响应报头中
void set_header(const char *key, const char *val);
//设置正文——可以设置类型
void set_content(const std::string &s, const char *content_type);
};

Server类

Server类就是httplib中用于搭建服务器的类

 
class Server {
        //Handler一个函数指针,它的返回值为void,参数是Request,和Response
        using Handler = std::function<void(const Request &, Response &)>;
        //Handlers是一个映射表,将请求资源和处理函数映射在一起
        using Handlers = std::vector<std::pair<std::regex, Handler>>;
        //将Get方法的请求资源与处理函数加载到Handlers表中
        Server &Get(const std::string &pattern, Handler handler);
        Server &Post(const std::string &pattern, Handler handler);
        Server &Put(const std::string &pattern, Handler handler);
        Server &Patch(const std::string &pattern, Handler handler);  
        Server &Delete(const std::string &pattern, Handler handler);
        Server &Options(const std::string &pattern, Handler handler);
        //线程池
        std::function<TaskQueue *(void)> new_task_queue;
        //搭建并启动http
        bool listen(const char *host, int port, int socket_flags = 0);
 };

首先,Handler是一个回调的函数指针。Handlers是一个映射表。std::regex是正则表达式,用于匹配请求资源,即URL中的path。Handlers将请求的资源和处理函数进行映射。当服务器收到一个请求,解析Request,获取客户端请求的资源路径,在Handlers表中找是否存在映射关系,有则调用对应的Handler回调函数处理请求,无则返回404(请求资源不存在)。

Get,Post,Put,Patch,Delete,Options都是往Handlers表中设置映射关系

请求方法,请求资源和处理函数都是强相关的,如上表:

  • 只有http请求的请求方法是GET,且请求的资源是/Hello/a,服务器才会调用echoHelloA处理请求
  • 只要请求方法和请求资源在Handlers表中找不到映射的处理函数,http服务器就会返回404的http响应,表示请求资源不存在
  • Get("/Hello/a", echoHelloA):将请求方法为GET,请求资源为/Hello/a,与函数echoHelloA注册到Handlers表中

线程池的工作:

  1. 当服务器接收到一个http请求,会将该http请求放入线程池,线程池的线程会调用相应的函数解析http请求,形成一个Request对象
  2. 在Handlers映射表中查找有无对应请求方法和请求资源的处理函数,有则调用处理函数,并构建http响应
  3. 处理函数调用完后,将Responce构建成http响应,并将构建好的http响应返回给客户端

Client类

class Client {
    //构造一个客户端对象,传入服务器Ip地址和端口
    Client(const std::string &host, int port);
    //向服务器发送GET请求
    Result Get(const char *path, const Headers &headers);
    //向服务器发送Post请求
    //path是路径,body是request请求路径
    //content_length是正文大小
    //content_type是正文的类型
    Result Post(const char *path, const char *body, size_t content_length,
                const char *content_type);
        
    //以Post方法上传文件
    Result Post(const char *path, const MultipartFormDataItems &items);
}

httplib库搭建简单服务器&客户端

搭建服务器:

  1. 定义server对象
  2. 在Handlers表中注册相应请求方法和请求资源的处理函数
  3. listen绑定IP地址和端口号,启动服务器,监听连接和请求
#include <iostream>
#include "httplib.h"
#include <string>

int main()
{
    httplib::Server server;
    //设置处理函数
    //GET请求方法,/hello请求资源的映射函数
    server.Get("/hello", [](const httplib::Request& req, httplib::Response& resp){
        resp.set_content("Hello World!", "text/plain");
        resp.status = 200;
    });
    //GET请求方法,/number/数字请求资源的映射函数
    server.Get(R"(/number/(\d+))", [](const httplib::Request& req, httplib::Response& resp){
        //matches[0]是完整请求资源,后续都是捕捉的参数
        auto num = req.matches[1];
        resp.set_content(num, "text/plain");
        resp.status = 200;
    });
    //POST请求方法,/upload请求资源的映射函数
    server.Post("/upload", [](const httplib::Request& req, httplib::Response& resp){
        auto ret = req.has_file("file");//查找客户端是否上传file文件
        if(ret == false)
        {
            resp.set_content("没有上传file文件", "text/plain");
            resp.status = 404;
            return -1;
        }
        auto size = req.files.size();
        const auto& file = req.get_file_value("file");
        //获取到文件结构体——MultipartFormData 
        //构建Responce响应
        resp.body.clear();
        resp.body = file.filename;
        resp.body += "\n";
        resp.body += file.content;
        resp.set_header("Content-Type", "text/plain");
        resp.status = 200;
    });
    //启动服务器——绑定IP地址和端口号
    server.listen("0.0.0.0", 8080);
    return 0;
}

简单客户端

  1. 定义Clinet对象,绑定要连接的服务器的IP地址和端口号
  2. 构建请求
  3. 获取响应,处理响应
#include <iostream>
#include <string>
#include "httplib.h"

int main()
{
    //连接服务器
    httplib::Client client("106.55.180.125", 8080);
    //构建文件结构体
    httplib::MultipartFormData item;
    item.name = "file";
    item.filename = "Hello.txt";
    item.content = "Hello World!";
    item.content_type = "text/plain";
    //文件结构体数组——传输多个文件
    httplib::MultipartFormDataItems items;
    items.push_back(item);
    //发送请求
    auto res = client.Post("/upload", items);
    //接收并处理响应
    std::cout << res->status << std::endl;
    std::cout << res->body << std::endl;
}

;