项目Github主页 Coke。
上一篇文章通过几个示例介绍了如何使用Coke便捷地发起Http请求,本文延续上一个话题,将coke::HttpClient
的功能详细地介绍一下。
在C++ Workflow中,Http任务通常通过工厂函数创建,并且可以指定重试次数等参数。而在Coke中可以通过coke::HttpClient
来创建Http任务。首先介绍一下与任务相关的参数
struct HttpClientParams {
// 当请求失败时,支持自动进行重试操作,默认不重试
int retry_max = 0;
// 连接创建完成后,将请求完全发出的超时时间,默认不超时,单位毫秒
int send_timeout = -1;
// 请求发出后,客户端接收到完整回复的超时时间,默认不超时
int receive_timeout = -1;
// 连接保活时间,默认60秒
int keep_alive_timeout = 60 * 1000;
// Http任务在框架内自动重定向的最大次数,默认为0
int redirect_max = 0;
// 通过Http代理发送请求,若不使用代理则指定为空串
// 格式为 http://proxy.host:port/ 或 http://user:[email protected]:port/
std::string proxy;
};
coke::HttpClient
目前有三个接口用于创建任务
url
创建简单的Http Get任务url
、method
、header
、body
创建任务coke::HttpRequest
准备好请求,再创建任务具体使用方式参考下述示例代码
#include
#include
#include
#include
#include "coke/coke.h"
#include "coke/http_client.h"
#include "coke/http_utils.h"
void show_response(const coke::HttpResponse &resp) {
std::cout << resp.get_http_version() << ' '
<< resp.get_status_code() << ' '
<< resp.get_reason_phrase() << std::endl;
// 使用 coke::HttpHeaderCursor 方便地遍历所有header
for (const coke::HttpHeaderView &header : coke::HttpHeaderCursor(resp))
std::cout << header.name << ": " << header.value << std::endl;
std::cout << "\n";
// 为了简洁起见,省略了Http body内容的输出
if (resp.is_chunked()) {
// 对于Chunk编码的Http body,可使用coke::HttpChunkCursor来遍历
for (std::string_view chunk : coke::HttpChunkCursor(resp))
std::cout << "chunk body length " << chunk.size() << std::endl;
}
else {
// 对于非Chunk编码的Http body,可使用coke::http_body_view函数获取
std::string_view body_view = coke::http_body_view(resp);
std::cout << "\nbody length " << body_view.size() << std::endl;
}
}
coke::Task<> simple_get(coke::HttpClient &cli, const std::string &url) {
coke::HttpResult result;
result = co_await cli.request(url);
if (result.state != coke::STATE_SUCCESS)
std::cerr << coke::get_error_string(result.state, result.error) << std::endl;
else
show_response(result.resp);
}
coke::Task<> with_header_body(coke::HttpClient &cli, const std::string &url) {
coke::HttpResult result;
std::vector<std::pair<std::string, std::string>> header;
std::string body;
header.emplace_back("User-Agent", "coke-http-client");
result = co_await cli.request(url, "HEAD", header, body);
if (result.state != coke::STATE_SUCCESS)
std::cerr << coke::get_error_string(result.state, result.error) << std::endl;
else
show_response(result.resp);
}
coke::Task<> with_req(coke::HttpClient &cli, const std::string &url) {
coke::HttpResult result;
coke::HttpRequest req;
req.set_method("GET");
req.set_request_uri("/");
req.set_http_version("HTTP/1.1");
req.set_header_pair("User-Agent", "coke-http-client");
req.append_output_body("");
result = co_await cli.request(url, std::move(req));
if (result.state != coke::STATE_SUCCESS)
std::cerr << coke::get_error_string(result.state, result.error) << std::endl;
else
show_response(result.resp);
}
void http_cli(const std::string &url, const std::string &proxy) {
coke::HttpClientParams params;
params.retry_max = 2;
params.redirect_max = 2;
params.proxy = proxy;
// 使用指定的参数创建客户端
coke::HttpClient cli(params);
// 依次发起Http任务
coke::sync_wait(simple_get(cli, url));
coke::sync_wait(with_header_body(cli, url));
coke::sync_wait(with_req(cli, url));
// 也可以同时发起多个任务,但展示结果的函数没有互斥锁保护,结果可能错乱
//coke::sync_wait(
// simple_get(cli),
// with_header_body(cli),
// with_req(cli)
//);
}
// ./http_client url [proxy]
int main(int argc, char *argv[]) {
std::string url{"https://sogou.com/"};
std::string proxy;
if (argc > 1 && argv[1])
url.assign(argv[1]);
if (argc > 2 && argv[2])
proxy.assign(argv[2]);
http_cli(url, proxy);
return 0;
}
目前的代理仅支持http代理,而http代理又有两种模式
request uri
部分改写为被请求的url,发送到代理服务器对于模式1,因为不是由原生的C++ Workflow
的HttpTask
支持的功能,所以重定向功能会被禁用,且根据上一篇文章的讨论,使用coke可以很便捷地实现重定向的功能。
实际上,coke提供的coke::HttpClient
是封装了workflow的Http任务的语法糖,它本身并不维护任务的状态等信息。即使不使用coke::HttpClient
,熟悉C++ Workflow
的同学也可以手动创建原生的HttpTask
并结合coke
提供的组件以协程的方式发起任务,但由于会带来关于生命周期的一系列问题,此处不展开讨论,后续会补充到coke
的项目文档当中去。
本系列文章同步发布于个人网站和知乎专栏,转载请注明来源,以便读者及时获取最新内容及勘误。