【问题标题】:Handling HTTP responses from libcurl over multiple callbacks通过多个回调处理来自 libcurl 的 HTTP 响应
【发布时间】:2012-10-15 20:35:32
【问题描述】:

我正在使用 libcurl 发送 HTTP 发布请求并随后处理响应。收到响应后,库使用通过curl_easy_setopt 提供给CURLOPT_WRITEFUNCTION 属性的函数回调我的程序。

// callback function
std::size_t on_data(const char* buffer, const std::size_t size, const std::size_t nmemb, void* context);

从文档中不清楚你可以将数据留在缓冲区中(通过从回调返回 0)或者你必须将数据复制到本地缓冲区,然后在每个后续回调中继续附加到这个缓冲区,直到你收到整个消息。

我的问题是:

  1. 获取整个消息长度的最佳方法是什么?是来自Content-Length 标头通过CURLOPT_WRITEHEADER 吗?
  2. 有没有办法避免复制部分响应,而是等待收到最终消息,然后对其进行完整处理?

【问题讨论】:

    标签: c++ curl libcurl


    【解决方案1】:

    CURLOPT_WRITEFUNCTION 选项而言,文档明确指出该函数必须:

    [r]返回实际处理的字节数。 如果该金额与传递给您的函数的金额不同, 它会向库发出错误信号。这将中止传输 并返回 CURLE_WRITE_ERROR。

    因此,除非您想明确中止传输,否则您应该始终返回实际大小,即size * nmemb。此外,如果您选择使用本地缓冲区,那么是的,您必须注意将传入数据复制到其中(并注意重新分配),如 docs/examples/getinmemory.c 示例代码所示。

    请注意,如果您不想使用内存缓冲区,您也可以通过 CURLOPT_WRITEDATA 选项使用文件,如图所示,例如通过docs/examples/url2file.cdocs/examples/fopen.c 示例。

    否则:

    1. 我想说,要先验地检查您愿意获取的资源的大小,那么您应该执行HEAD 请求(通过将CURLOPT_NOBODY 设置为1 和CURLOPT_HEADER 设置为1)要求通过CURLOPT_WRITEHEADERCURLOPT_WRITEFUNCTION写入HTTP标头,最后解析Content-Length值。但是:这绝对是不是处理 POST 请求的方式,因为它不是幂等的!

    2. 如果您不习惯使用不断增长的内存缓冲区(例如,可能是因为您期望响应非常大),那么您应该使用使用 CURLOPT_WRITEDATA 处理文件的功能,以便响应逐渐写入磁盘。完成后,使用您的文件 - 以您想要的方式包含整个消息。

    【讨论】:

    • 首先,谢谢。写入文件不是一种选择,我正在流式传输实时市场数据,因此延迟(尽管供应商选择 HTTP 进行交付)很重要。对于 (1) 单个 POST 请求肯定会返回单个响应,因此单个 Content-Length?当然,幂等性只会来自多个请求吗?对于(2)我认为这意味着没有办法将数据留在 libcurl 拥有的缓冲区中并在以后的回调中复制?
    • (1) 要清楚,我认为这里的 HEAD 选项不是一个选项...正确,因为您需要执行 POST 而不是 GET :/ (2 ) 我不知道这种可能性,并且在curl_easy_getinfo API 中没有公开这样的事情(参见doc)。问题是,如果您不想使用文件,为什么要避免使用内存缓冲区并即时写入它(这是一个 nominal 用例)?如果您正确地预分配缓冲区(以避免过多的重新分配),恕我直言,应该没有性能损失。
    • 经过反思,我认为 memcpy'ing 到预分配的缓冲区应该没问题。就(1)而言,我仍然不清楚为什么POST 意味着HEAD 不合适,毕竟返回了一个标头。对于 (2),CURLINFO_CONTENT_LENGTH_DOWNLOAD 看起来非常有用。
    • (1) POST-ing 第一次,阅读标题以了解内容长度,然后重新POST-ing 绝对不是一个聪明的选择 + 你可能会面临幂等性问题。在大多数情况下,执行HEAD 请求根本不可能,例如w/ RESTful 端点或仅仅因为您需要有效地发布一些内容以获得正确的响应(但这里再次取决于您的 Web 服务)。 (2) 如果您使用内存缓冲区,则不需要它(顺便说一句,尝试使用实际大小而不是典型响应大小预先分配它)。
    • 我想我理解轻微的混淆来源 - 我曾计划在单个 POST 上调用 CURLOPT_HEADERFUNCTIONCURLOPT_WRITEFUNCTION。我现在看到,当收到所有数据时,这将不是必需的,curl_easy_perform 将返回并且内部缓冲区将可用于所有数据。
    猜你喜欢
    • 2018-12-27
    • 2017-02-25
    • 1970-01-01
    • 2011-02-10
    • 2013-09-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-15
    相关资源
    最近更新 更多