直接复制sion.h到自己的项目下include
Include sion.h directly
auto resp = sion::Fetch(url);
std::cout << resp.StrBody() << std::endl;
std::cout << resp.GetHeader().Get("content-type") << std::endl;
auto resp = sion::Request()
.SetBody(R"({ "hello": "world" })")
.SetHeader("Content-type", "application/json")
.SetUrl("http://www.httpbin.org/post")
.SetHttpMethod("POST")
.Send();
std::cout << resp.StrBody() << std::endl;
- Sion是一个轻量级简单易用的c++请求库
- 仅单个头文件,自带std::string的扩展
- 跨平台,支持linux, win, mac...
- 有着良好的异步支持,可以选择以自己喜欢的方式发送异步请求, callback, await, 事件循环, etc.
- 支持文本及二进制的响应体
- 支持分块(chunked)的传输编码
- 支持FormData&单独的二进制载荷请求
- 支持http代理
- 支持http,https请求。https需要安装openssl(推荐使用vcpkg),如果不需要可以使用 #define SION_DISABLE_SSL 关闭。如果使用了代理,即使是没启用ssl,也可以请求https链接。
sion在此版本后对异步增加了巨大的支持,相对于之前的版本依旧保持了同步api+异步库的方式,尽可能保持简单轻量,尽管性能不是很理想但性能从来就不是sion的最优先考虑的东西,但性能也不算太差 粗略的性能参考。
sion的异步支持依赖于sion内置的Async线程池,函数可参考Async。
sion::Async async_thread_pool;
async_thread_pool.Start(); // 启动线程池,创建子线程,子线程接受任务开始工作
sion::Async处理异步有3种方式
- 使用回调
async_thread_pool.Run([=] { return sion::Request().SetUrl(url).SetHttpMethod(sion::Method::Get); },
[](sion::AsyncResponse async_resp) { std::cout << "AsyncCallback " << async_resp.resp.Status() << std::endl; });
- 使用await
在无回调时提交任务到线程池会返回给你一个id,通过这个id我们可以使用await在当前线程上等待请求完成。
auto id = async_thread_pool.Run([=] { return sion::Request().SetUrl(url).SetHttpMethod(sion::Method::Get); });
// 在Run后的这段时间里当前线程可以先去干其他的活,等待需要使用响应时再使用await获取响应。
auto pkg = async_thread_pool.Await(id);
std::cout << "AsyncAwait " << pkg.resp.GetHeader().Data().size() << pkg.err_msg << std::endl;
// 你可以给await添加超时时间,如果超时会抛出AsyncAwaitTimeout
try
{
auto id = async_thread_pool.Run([=] { return sion::Request().SetUrl(url).SetHttpMethod(sion::Method::Get); });
auto pkg = async_thread_pool.Await(id, 10);
}
catch (const std::exception& e)
{
std::cerr << e.what() << '\n';
}
- 使用GetAvailableResponse
这种方式是通过不断获取调取此函数来获取想要的响应,主要还是方便与事件循环集成。
const int num = 100;
for (size_t i = 0; i < num; i++)
{
async_thread_pool.Run([=] { return sion::Request().SetUrl(url).SetHttpMethod(sion::Method::Get); });
}
int i = 0;
while (i <= num)
{
std::this_thread::sleep_for(std::chrono::seconds(1));
auto async_resps = async_thread_pool.GetAvailableResponse();
if (async_resps.size())
{
i += async_resps.size();
std::cout << "AsyncGetAvailableResponse got resp size:" << async_resps.size() << std::endl;
}
}
上面几种方式都会返回AsyncResponse,通过这个可以获取异步请求的响应体,id,以及错误信息
包含普通请求,代理,二进制数据发送,FormData,Async等 查看参考
// 静态请求方法
Response Fetch(String url, Method method = Get, Header header = Header(), String body = "");
该类用来处理请求响应
// 返回接收到的响应体
const vector<char>& Body();
// 将接收到的响应体转成字符串,如果你能确保接收到的数据是字符串,可以直接使用这个
String StrBody();
String Code();
String Status();
int ContentLength();
const Header& GetHeader();// 获取响应头 参考 [Header](#Header)
该类用来处理发送请求
//支持链式设置属性
Request& SetHttpMethod(String other) ;
Request& SetUrl(String url);
Request& SetBody(String body); // 设置响应体,字符串
Request& SetBody(Payload::Binary body); // 设置响应体,二进制文件
Request& SetBody(Payload::FormData body); // 设置响应体,表单数据
Request& SetHeader(Header header);
Request& SetHeader(String k, String v);
Request& SetProxy(HttpProxy proxy); // 设置代理,仅在http可用
Response Send(); // 发送请求
响应头和请求头
// 添加一个键值对到头中
void Add(String k, String v);
// 获取头的键所对应的所有值
vector<String> GetAll(String key);
// 获取头的键所对应的值,以最后一个为准
String Get(String key);
//删除目标键值对,返回一个bool指示操作是否成功
bool Remove(String key);
// 删除所有的键值对
void RemoveAll(String key)
// 返回数据本体
const vector<pair<String, String>>& Data();
该类依赖处理sion的异步请求,内置了个小型的线程池,提供了callback,await,事件循环三种方式让你来处理异步的请求。线程池会在析构时退出启动的所有线程。
// 设置线程池的线程数量,即能够同时请求或者是运行请求回调的数量, 如果进行比较重的回调可以设置成std::thread::hardware_concurrency(),以减少上下文切换开销
Async& SetThreadNum(int num);
// 设置线程池是否以阻塞当前线程的方式运行
Async& SetBlock(bool wait);
// 设置await是否在接收到包含错误消息的响应时抛异常
Async& SetThrowIfHasErrMsg(bool op);
// 启动线程池
void Start();
// 添加一个请求到线程池的任务队列, 返回一个请求的id,id可用于await或者是查找对应的请求
int Run(std::function<Request()> fn);
// 添加一个请求和回调到线程池的任务队列,在请求完成后会在请求的线程执行回调
void Run(std::function<Request()> fn, std::function<void(AsyncResponse)> cb);
//在当前线程等待直到目标请求可用。id:Async::Run返回的id,timeout_ms 超时时间单位毫秒,默认永不超时
AsyncResponse Await(int id, int timeout_ms);
// 获得当前可用的响应,如果你添加一个请求到线程池的任务队列,且没有回调或者使用await取获取,那么可用通过这种方式获取。适用场合是一般是在事件循环里面
vector<AsyncResponse> GetAvailableResponse();
Payload名称空间包含2种请求体可用的数据
namespace Payload
{
struct Binary
{
std::vector<char> data; // 数据本体
String file_name; // 文件名,在提交formdata如果写了,则会带上文件名的信息
String type; // 文件mime类型,如果写了在直接使用二进制时会添加到正文的Content-Type,在formdata则是添加到子部分的
};
class FormData
{
void Append(String name, Binary value); // 添加一个新的二进制值
void Append(String name, String value); // 添加一个新的字符串键
bool Remove(String key); // 移除一项,返回是否成功
const std::vector<std::pair<String, std::vector<char>>>& Data() const; // 返回数据本体
};
}
该类继承std::string,用法基本一致,拓展了几个函数
//使用字符串分割
//flag 分割标志,返回的字符串向量会剔除,flag不要用char,会重载不明确
//num 分割次数,默认0即分割到结束,例num=1,返回开头到flag,flag到结束size=2的字符串向量
//skip_empty 跳过空字符串,即不压入length==0的字符串
std::vector<String> Split(String flag, int num = -1, bool skip_empty = true);
//清除前后的字符
//target 需要清除的字符默认空格空格姬换行符
String Trim(String target = " \n\r");
//包含字母
bool HasLetter();
// 转成小写,返回一个新的字符串
String ToLowerCase();
// 转成大写,返回一个新的字符串
String ToUpperCase();
//返回搜索到的所有位置
//flag 定位标志
//num 搜索数量,默认直到结束
std::vector<int> FindAll(String flag, int num = -1);
//字符串替换,会修改原有的字符串,而不是返回新的
String& Replace(String old_str, String new_str);
Proxy
struct HttpProxy
{
int port; // 目标端口
String host; // 目标主机,ip
};