目录
认识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;//请求资源路径——URLHeaders headers;//头部字段std::string body;//正文部分std::string version;//协议版本Params params;//查询字符串MultipartFormDataMap files;//客户端上传文件的信息Ranges ranges;//实现断点续传的请求区间//提供的API//查询头部字段key是否存在bool has_header(const char *key) const;//获取头部字段的valuestd::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.1int 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,和Responseusing 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;//搭建并启动httpbool 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表中
线程池的工作:
- 当服务器接收到一个http请求,会将该http请求放入线程池,线程池的线程会调用相应的函数解析http请求,形成一个Request对象
- 在Handlers映射表中查找有无对应请求方法和请求资源的处理函数,有则调用处理函数,并构建http响应
- 处理函数调用完后,将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库搭建简单服务器&客户端
搭建服务器:
- 定义server对象
- 在Handlers表中注册相应请求方法和请求资源的处理函数
- 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;
}
简单客户端
- 定义Clinet对象,绑定要连接的服务器的IP地址和端口号
- 构建请求
- 获取响应,处理响应
#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;
}