【问题标题】:libcurl ignore body in case HTTP non-ok如果 HTTP 不正常,libcurl 会忽略正文
【发布时间】:2020-03-03 17:56:02
【问题描述】:

我经常使用 curl 下载文件。然而,服务器做了一件棘手的事情:它返回非 200 代码并仍然发送一些数据。问题是我有数据写入后的HTTP代码,但如果不是200我不想写任何东西。有谁知道不将数据存储在磁盘或内存上的方法?

curl_easy_setopt(curl, CURLOPT_URL, url);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curlWriteHandler);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, ptr);
res = curl_easy_perform(curl);
if (res == CURLE_OK) {
    return 0;
}

long response_code;
curl_easy_getinfo(curl_.get(), CURLINFO_RESPONSE_CODE, &response_code);
if (response_code != 200) {
    return 0;
}

size_t curlWriteHandler(char* chars, size_t size, size_t nmemb, void* userp) {
    // write to file

    return size * nmemb;
}

【问题讨论】:

  • 在非200的情况下下载的是什么数据?
  • 这是一些 html 错误。

标签: c curl libcurl


【解决方案1】:

设置 CURLOPT_FAILONERROR 应该可以处理 4xx 和 5xx 错误。

当使用此选项并检测到错误时,将导致连接关闭并返回 CURLE_HTTP_RETURNED_ERROR。

curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1L);

关闭连接对我不好,重用一个很重要。你还能想点别的吗?

很遗憾,我找不到让CURLOPT_FAILONERROR 不关闭连接的方法。

另一个选项是让写入函数知道响应。不幸的是 curl 句柄没有传递到回调中。

我们可以将curl 变量设为全局变量。或者我们可以利用 void *userdata 选项来写入回调,并传入一个包含 curl 句柄和缓冲区的结构。

这是一个粗略的草图,展示了写回调如何访问响应代码并保存响应正文。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <curl/curl.h>

typedef struct {
    CURL *curl;
    char *buf;
} curl_write_data;

size_t curlWriteHandler(char* chars, size_t size, size_t nmemb, void* userp) {
    curl_write_data *curl_data = (curl_write_data*)userp;
    long response_code;
    curl_easy_getinfo(curl_data->curl, CURLINFO_RESPONSE_CODE, &response_code);
    printf("Response: %ld\n", response_code);

    // Now we can save if we like.
    if( response_code < 300 ) {
        curl_data->buf = malloc(size*(nmemb+1));
        strcpy(curl_data->buf, chars);
        strcat(curl_data->buf, "\0");
        return size * nmemb;
    }
    else {
        return  0;
    }
}

int main() {
    CURL *curl = curl_easy_init();
    if(!curl) {
        perror("Cant' init curl");
    }

    curl_write_data curl_data = { .curl = curl, .buf = NULL };
    curl_easy_setopt(curl, CURLOPT_URL, "http://example.com/alsdfjalj");
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curlWriteHandler);
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, &curl_data);

    curl_easy_perform(curl);

    if( curl_data.buf ) {
        puts(curl_data.buf);
    }
}

我不确定这是否是最好的主意,这是我想出的。

【讨论】:

  • 感谢您的回复。关闭连接对我不利,重用一个很重要。你还能想点别的吗?
  • @Yuki 我想出了一些办法。查看更新的答案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-06-25
  • 2015-07-20
  • 1970-01-01
  • 2021-02-04
  • 1970-01-01
相关资源
最近更新 更多