Curl for People (crp)库介绍——高级用法

1、响应对象 (Response Objects)

Response对象是数据包。他们的唯一目的是在请求结束时提供客户端信息 - 在API Response返回给您之后,没有任何API使用它。这个推理促使决定使响应的成员字段公开和可变。
一个Response有一下几个领域:

long status_code; // The HTTP status code for the request
std::string text; // The body of the HTTP response
Header header;    // A map-like collection of the header fields
Url url;          // The effective URL of the ultimate request
double elapsed;   // The total time of the request in seconds
Cookies cookies;  // A map-like collection of cookies returned in the request

而且访问非常简单:

auto r = cpr::Get(cpr::Url{"http://www.httpbin.org/get"});
if (r.status_code >= 400) {
    std::cerr << "Error [" << r.status_code << "] making request" << std::endl;
} else {
    std::cout << "Request took " << r.elapsed << std::endl;
    std::cout << "Body:" << std::endl << r.text;
}

这Header本质上是一个具有重要修改的地图。按照RFC 7230的要求,其密钥不区分大小写:

auto r = cpr::Get(cpr::Url{"http://www.httpbin.org/get"});
std::cout << r.header["content-type"] << std::endl;
std::cout << r.header["Content-Type"] << std::endl;
std::cout << r.header["CoNtEnT-tYpE"] << std::endl;

所有这些应该打印相同的值”application/json”。类似地,Cookie也可以通过类似地图的界面访问,但它们不区分大小写:

auto r = cpr::Get(cpr::Url{"http://www.httpbin.org/cookies/set?cookies=yummy"});
std::cout << r.cookies["cookies"] << std::endl; // Prints yummy
std::cout << r.cookies["Cookies"] << std::endl; // Prints nothing

正如你所看到的,这个Response对象是完全透明的。它的所有数据字段都可以随时访问,因为它只有在有信息可以沟通的时候才有用,所以当你完成它时,可以让它安全地超出范围。

2、请求标题 (Request Headers)

说到这个Header,你可以在请求调用中设置自定义标题。该对象完全相同:

auto r = cpr::Get(cpr::Url{"http://www.httpbin.org/headers"},
                  cpr::Header{{"accept", "application/json"}});
std::cout << r.text << std::endl;

/*
 * "headers": {
 *   "Accept": "application/json",
 *   "Host": "www.httpbin.org",
 *   "User-Agent": "curl/7.42.0-DEV"
 * }
 */

您可能已经注意到之间的相似性Header,Parameters,Payload,和Multipart。他们都有以下形式的构造函数:

auto header = cpr::Header{{"header-key", "header-value"}};
auto parameters = cpr::Parameters{{"parameter-key", "parameter-value"}};
auto payload = cpr::Payload{{"payload-key", "payload-value"}};
auto multipart = cpr::Multipart{{"multipart-key", "multipart-value"}};

这不是偶然的 - 所有这些都是类地图对象,它们的语法是相同的,因为它们的语义完全取决于对象类型。此外,它的实用性有Parameters,Payload和Multipart是可交换的,因为有时的API没有严格区分它们。

3、会话对象 (Session Objects)

在引擎盖下,Session在执行请求之前,所有对主API的调用都会修改名为a的对象。这是图书馆唯一真正有状态的一部分,对于大多数应用程序来说,没有必要Session直接采取行动,宁愿让图书馆为你处理。
但是,如果持有状态有用,可以使用Session:

auto url = cpr::Url{"http://www.httpbin.org/get"};
auto parameters = cpr::Parameters{{"hello", "world"}};
cpr::Session session;
session.SetUrl(url);
session.SetParameters(parameters);

auto r = session.Get();             // Equivalent to cpr::Get(url, parameters);
std::cout << r.url << std::endl     // Prints http://www.httpbin.org/get?hello=world

auto new_parameters = cpr::Parameters{{"key", "value"}};
session.SetParameters(new_parameters);

auto new_r = session.Get();         // Equivalent to cpr::Get(url, new_parameters);
std::cout << new_r.url << std::endl // Prints http://www.httpbin.org/get?key=value

Session实际上公开了两个不同的界面来设置相同的选项。如果你想要,你可以做到这一点,而不是上述:

auto url = cpr::Url{"http://www.httpbin.org/get"};
auto parameters = cpr::Parameters{{"hello", "world"}};
cpr::Session session;
session.SetOption(url);
session.SetOption(parameters);
auto r = session.Get();

这很重要,所以它强调:对于每个配置选项(如Url,Parameters),都有相应的方法Set和aSetOption()。第二个接口是为了促进模板元编程魔术,让API暴露无序方法。
所有这一切的关键实际上就是libcurl的设计方式。它使用基于策略的设计,依赖于配置单个库对象(curl句柄)。配置到该对象中的每个选项都以大部分正交的方式更改其行为。
Session利用它并公开一个更现代化的界面,免除了libcurl巨大的浪费。了解基于策略的libcurl设计对于理解Session对象的行为方式非常重要。

4、异步请求 (Asynchronous Requests)

制作异步请求使用类似但独立的接口:

auto fr = cpr::GetAsync(cpr::Url{"http://www.httpbin.org/get"});
// Sometime later
auto r = fr.get(); // This blocks until the request is complete
std::cout << r.text << std::endl;

电话是除,而不是其他相同的Get,它是GetAsync。与POST请求类似,您可以调用PostAsync。异步调用的返回值实际上是一个std::future<Response>

auto fr = cpr::GetAsync(cpr::Url{"http://www.httpbin.org/get"});
fr.wait() // This waits until the request is complete
auto r = fr.get(); // Since the request is complete, this returns immediately
std::cout << r.text << std::endl;

你甚至可以把一堆请求放入一个std容器中,并在以后使用它们:

auto container = std::vector<std::future<cpr::Response>>{};
auto url = cpr::Url{"http://www.httpbin.org/get"};
for (int i = 0; i < 10; ++i) {
    container.emplace_back(cpr::GetAsync(url, cpr::Parameters{{"i", std::to_string(i)}}));
}
// Sometime later
for (auto& fr: container) {
    auto r = fr.get();
    std::cout << r.text << std::endl;
}

这里要做的一个重要的注意事项是传递给异步调用的参数被复制。在引擎盖下,通过库的API的异步调用完成std::async。默认情况下,为了内存安全,所有参数都被复制(或者在临时移动时),因为没有语法级别保证参数超出请求的范围。
可以强制std::async使用此默认值,以便参数传递参数而不是值。然而,cpr::Async目前不支持强制传递,尽管这是为将来的版本计划的。

5、异步回调(Asynchronous Callbacks)

C ++请求还支持异步请求的回调接口。使用回调接口,传递一个仿函数(lambda,函数指针等)作为第一个参数,然后传入其他通常在阻塞请求中选择的选项。函子需要有一个参数,一个Response对象 - 当请求完成并且函数体执行时,这个响应被填充。
这里有一个简单的例子:

auto future_text = cpr::GetCallback([](cpr::Response r) {
        return r.text;
    }, cpr::Url{"http://www.httpbin.org/get"});
// Sometime later
if (future_text.wait_for(std::chrono::seconds(0)) == std::future_status::ready) {
    std::cout << future_text.get() << std::endl;
}

这里有几个关键特性需要指出:
1. 返回值是a std::string。这不是硬编码的 - 回调可以自由返回任何值!当需要获取该值时,检查请求是否完成,然后简单地.get()调用将来的值来获取正确的值。这种灵活性使回调界面非常简单,通用且高效!
2. lambda捕获是空的,但绝对不需要。任何可以在lambda中捕获的东西通常都可以在传入回调接口的lambda中捕获。这种额外的灵活性向量使得它非常适合使用lambda表达式,尽管任何具有Response参数的函子都可以编译和工作。
另外,你可以Response用const Response&参数而不是简单地强制执行不变性Response。

6、设置超时 (Setting Timeout)

如果您有严格的时间要求,可以为您的请求设置超时时间:

#include <assert.h>

auto r = cpr::Get(cpr::Url{"http://www.httpbin.org/get"},
                  cpr::Timeout{1000}); // Let's hope we aren't using Time Warner Cable
assert(r.elapsed <= 1); // Less than one second should have elapsed

设置Timeout选项可设置传输操作可以承受的最大时间。由于C ++请求是建立在libcurl的基础上的,因此了解Timeout对请求做了什么设置很重要。你可以在这里找到更多关于特定libcurl选项的信息。

7、使用代理 (Using Proxies)

Proxies,就像Parameters是地图式的对象。设置一个很容易:

auto r = cpr::Get(cpr::Url{"http://www.httpbin.org/get"},
                  cpr::Proxies{{"http", "http://www.fakeproxy.com"}});
std::cout << r.url << std::endl; // Prints http://www.httpbin.org/get, not the proxy url

它看起来并不Proxies像一张地图那样有用,但在使用Session它时更明显:

cpr::Session session;
session.SetProxies({{"http", "http://www.fakeproxy.com"},
                    {"https", "http://www.anotherproxy.com"}})
session.SetUrl("http://www.httpbin.org/get");
{
    auto r = session.Get();
    std::cout << r.url << std::endl; // Prints http://wcww.httpbin.org/get after going
                                     // through http://www.fakeproxy.com
}
session.SetUrl("https://www.httpbin.org/get");
{
    auto r = session.Get();
    std::cout << r.url << std::endl; // Prints https://www.httpbin.org/get after going
                                     // through http://www.anotherproxy.com
}

设置Proxies一个Session可以让你通过使用不同的代理不同协议智能路由请求,而无需respecify什么,但该请求Url。

8、发送Cookies (SendingCookies)

之前您看到了如何从请求中获取cookie:

auto r = cpr::Get(cpr::Url{"http://www.httpbin.org/cookies/set?cookies=yummy"});
std::cout << r.cookies["cookies"] << std::endl; // Prints yummy
std::cout << r.cookies["Cookies"] << std::endl; // Prints nothing

您可以使用同一个对象发回Cookie:

auto r = cpr::Get(cpr::Url{"http://www.httpbin.org/cookies/set?cookies=yummy"});
auto another_r = cpr::Get(cpr::Url{"http://www.httpbin.org/cookies"}, r.cookies);
std::cout << another_r.text << std::endl;

/*
 * {
 *   "cookies": {
 *     "cookie": "yummy"
 *   }
 * }
 */

这是特别有用的,因为Cookies通常从服务器到客户端并返回到服务器。设置新的Cookies应该不会令人惊讶:

auto r = cpr::Get(cpr::Url{"http://www.httpbin.org/cookies"},
                  cpr::Cookies{{"ice cream", "is delicious"}});
std::cout << r.text << std::endl;

/*
 * {
 *   "cookies": {
 *     "ice%20cream": "is%20delicious"
 *   }
 * }
 */

请注意,按照RFC 2965的要求,cookie是如何使用url编码模式进行编码的。除了这个怪癖,使用Cookies相当简单,只是工作。

9、PUT和PATCH请求(PUT and PATCH Requests)

PUT和PATCH请求与POST请求的工作方式相同,唯一的修改是指定的HTTP方法是”PUT”或”PATCH”不是”POST”。当你调用的API的语义实现这些请求的特殊行为时使用它:

#include <assert.h>

// We can't POST to the "/put" endpoint so the status code is rightly 405
assert(cpr::Post(cpr::Url{"http://www.httpbin.org/put"},
                 cpr::Payload{{"key", "value"}}).status_code == 405);

// On the other hand, this works just fine
auto r = cpr::Put(cpr::Url{"http://www.httpbin.org/put"},
                  cpr::Payload{{"key", "value"}});
std::cout << r.text << std::endl;

/*
 * {
 *   "args": {},
 *   "data": "",
 *   "files": {},
 *   "form": {
 *     "key": "value"
 *   },
 *   "headers": {
 *     ..
 *     "Content-Type": "application/x-www-form-urlencoded",
 *     ..
 *   },
 *   "json": null,
 *   "url": "https://httpbin.org/put"
 * }
 */

大多数情况下,PUT用于使用新对象更新现有对象。当然,这并不能保证任何特定的API以这种方式使用PUT语义,所以只有在它有意义时才使用它。这是一个示例PATCH请求,它基本相同:

#include <assert.h>

// We can't POST or PUT to the "/patch" endpoint so the status code is rightly 405
assert(cpr::Post(cpr::Url{"http://www.httpbin.org/patch"},
                 cpr::Payload{{"key", "value"}}).status_code == 405);
assert(cpr::Put(cpr::Url{"http://www.httpbin.org/patch"},
                cpr::Payload{{"key", "value"}}).status_code == 405);

// On the other hand, this works just fine
auto r = cpr::Patch(cpr::Url{"http://www.httpbin.org/patch"},
                    cpr::Payload{{"key", "value"}});
std::cout << r.text << std::endl;

/*
 * {
 *   "args": {},
 *   "data": "",
 *   "files": {},
 *   "form": {
 *     "key": "value"
 *   },
 *   "headers": {
 *     ..
 *     "Content-Type": "application/x-www-form-urlencoded",
 *     ..
 *   },
 *   "json": null,
 *   "url": "https://httpbin.org/patch"
 * }
 */

和PUT一样,只有当您发送请求的API支持该方法时,PATCH才有效。
其他请求方法
C ++请求还支持DELETE,HEAD以及OPTIONS在预期的形式的方法:

// Regular, blocking modes
auto delete_response = cpr::Delete(cpr::Url{"http://www.httpbin.org/delete"});
auto head_response = cpr::Head(cpr::Url{"http://www.httpbin.org/get"});
auto options_response = cpr::OPTIONS(cpr::Url{"http://www.httpbin.org/get"});

// Asynchronous, future mode
auto async_delete_response = cpr::DeleteAsync(cpr::Url{"http://www.httpbin.org/delete"});
auto async_head_response = cpr::HeadAsync(cpr::Url{"http://www.httpbin.org/get"});
auto async_options_response = cpr::OptionsAsync(cpr::Url{"http://www.httpbin.org/get"});

// Asynchronous, callback mode
auto cb_delete_response = cpr::DeleteCallback([](cpr::Response r) {
        return r.text;
    }, cpr::Url{"http://www.httpbin.org/delete"});
auto cb_head_response = cpr::HeadCallback([](cpr::Response r) {
        return r.status_code;
    }, cpr::Url{"http://www.httpbin.org/get"});
auto cb_options_response = cpr::OptionsCallback([](cpr::Response r) {
        return r.status_code;
    }, cpr::Url{"http://www.httpbin.org/get"});

目前,”PATCH”不是一种实施的HTTP方法。它很快就会成立,其机制将与上述例子相一致。

猜你喜欢

转载自blog.csdn.net/wanggao_1990/article/details/79806384
今日推荐