cpp-httplib
1. 介绍
C++ HTTP 库(cpp-httplib)是一个轻量级的 C++ HTTP 客户端/服务器库,它提供了简单的 API 来创建 HTTP 服务器和客户端,支持同步和异步操作。这种第三方网络库,可以让我们免去搭建服务器或客户端的时间,把更多的精力投入到具体的业务处理中,提高开发效率。以下是一些关于cpp-httplib 的主要特点:
- 轻量级:cpp-httplib 的设计目标是简单和轻量,只有一个头文件包含即可,不依赖于任何外部库。
- 跨平台:它支持多种操作系统,包括 Windows、Linux 和 macOS。
- 同步和异步操作:库提供了同步和异步两种操作方式,允许开发者根据需要选择。
- 支持 HTTP/1.1:它实现了 HTTP/1.1 协议,包括持久连接和管道化。
- Multipart form-data:支持发送和接收 multipart/form-data 类型的请求,这对于
文件上传非常有用。 - SSL/TLS 支持:通过使用 OpenSSL 或 mbedTLS 库,cpp-httplib 支持 HTTPS
和 WSS。 - 简单易用:API 设计简洁,易于学习和使用。
- 性能:尽管是轻量级库,但性能表现良好,适合多种应用场景。
- 社区活跃:cpp-httplib 有一个活跃的社区,不断有新的功能和改进被加入。
2. 安装
git clone https://github.com/yhirose/cpp-httplib.git
3. 类与接口
3.1 httplib请求
namespace httplib
{
// 文件信息结构体
struct MultipartFormData
{
std::string name; // 字段名称
std::string content; // 文件内容
std::string filename; // 文件名称
std::string content_type; // 文件类型
};
using MultipartFormDataItems = std::vector<MultipartFormData>;
struct Request
{
std::string method;//请求方法
std::string path;//请求资源路径
Headers headers;//请求报头
std::string body;//请求正文
Params params;//查询字符串
MultipartFormDataMap files;//保存的是客户端上传的文件信息
Ranges ranges;//用于实现文件断点续传的请求文件区间
//判断请求报头中有没有某个字段
bool has_header(const char *key) const;
//获取请求报头中对应的字段值
std::string get_header_value(const char *key, size_t id = 0) const;
//将key-val的字段值设定在http请求中
void set_header(const char *key, const char *val);
//判断对应的文件name是否存在,主要判断MultipartFormData里面的name是否存在
bool has_file(const char *key) const;
//获取对应的文件信息
MultipartFormData get_file_value(const char *key) const;
};
}
3.2 httplib响应
struct Response
{
std::string version;//响应版本
int status = -1;//响应状态码
std::string reason;
Headers headers;//响应报头
std::string body;//响应正文
std::string location; // 重定向位置
//设置正文内容+正文类型
void set_content(const std::string &s,const std::string &content_type);
//设置头部字段,以key val方式
void set_header(const std::string &key,const std::string &val);
};
3.3 httplib服务端
class Server
{
//Handler是对应请求资源路径的回调函数
using Handler = std::function<void(const Request &, Response &)>;
//Handlers是一个映射表,它映射的是请求资源路径和对应回调函数
using Handlers = std::vector<std::pair<std::regex, Handler>>
//对应方法设置对应请求路径和回调函数
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 &Delete(const std::string &pattern, Handler handler);
//启动服务器
bool listen(const std::string &host, int port);
};
Http请求对应每个请求方法都有自己的路由选择表。构建服务器的时候可以调用Server里面的Get(“/hello”,Hello),将请求方为GET,请求资源/hello,与函数Hello 注册 在Handlers表中。当http请求的请求方法是GET方法,且请求资源是/hello,那么服务器则会调用Hello函数,构建相对应的http响应。
3.4 httplib客户端
Get接口请求服务器对应请求路径的资源,请求成功后返回一个result值,这个值就是一个response类型,信息通过返回值进行获得。
post接口是上传一个文件信息给服务器,重载了两个函数,一个是通过MultipartFormData类型进行组织好文件内容,然后插入到MultipartFormDataItems数组中上传,这种方式是可以在一个请求中上传多个文件信息,另一个则是只针对一个文件信息上传。
class Client
{
//构造一个客户端对象,传入服务器Ip地址和端口
explicit Client(const std::string &host, int port);
//向服务器发送GET请求
Result Get(const std::string &path);
Result Get(const std::string &path, const Headers &headers);
//向服务器发送Post请求
//path是路径
//body是正文
//content_type是正文的类型
Result Post(const std::string &path, const std::string &body,const std::string &content_type);
//以Post方法上传文件
Result Post(const char *path, const MultipartFormDataItems &items);
Result Put(const std::string &path, const std::string &body,const std::string &content_type);
Result Delete(const std::string &path, const std::string &body,const std::string &content_type);
};
4. 使用
4.1 服务端
#include<iostream>
#include"cpp-httplib/httplib.h"
void Hi(const httplib::Request& req,httplib::Response& rsp)
{
std::cout<<req.method<<std::endl;
std::cout<<req.path<<std::endl;
std::string res = "<html><body><h1>你好世界!</hi></body></html>";
rsp.set_content(res,"text/html");
}
void File(const httplib::Request& req,httplib::Response& rsp)
{
bool ret = req.has_file("file");
if(ret == false)
{
std::cout<<"文件不存在"<<std::endl;
return;
}
auto file = req.get_file_value("file");
std::cout<<file.name<<std::endl;
std::cout<<file.filename<<std::endl;
std::cout<<file.content<<std::endl;
std::cout<<file.content_type<<std::endl;
}
int main()
{
httplib::Server server;
server.Get("/Hi",Hi);
server.Post("/File",File);
server.listen("0.0.0.0",8080);
return 0;
}
4.2 客户端
#include<iostream>
#include"cpp-httplib/httplib.h"
int main()
{
httplib::Client client("127.0.0.1",8080);
auto result1 = client.Get("/Hi");
if(result1 && result1->status == 200)
{
std::cout<<result1->body<<std::endl;
}
else
{
std::cerr<<"No content return"<<std::endl;
}
httplib::MultipartFormData data;
data.name = "file";
data.filename = "upload";
data.content = "upload content";
data.content_type = "text/plain";
httplib::MultipartFormDataItems items;
items.push_back(data);
auto result2 = client.Post("/File",items);
if(result2 && result2->status == 200)
{
std::cout<<result2->body<<std::endl;
}
else
{
std::cerr<<"upload error"<<std::endl;
}
return 0;
}
all:server client
servre:server.cc
g++ -o $@ $^ -std=c++17 -lpthread
client:client.cc
g++ -o $@ $^ -std=c++17 -lpthread