目录
认识httplib库
httplib库,是一个C++11单头文件的,轻量级的跨平台HTTP/HTTPS库,可以用来创建简单的HTTP服务器和客户端。其被设计成简单易用,适用于快速开发和测试,而不需要深入了解底层的HTTP协议。免去搭建服务器或客户端的时间,更快设计具体的业务处理,提高开发效率。
安装httplib库
在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表中
线程池的工作:
- 当服务器接收到一个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;
}