【问题标题】:How to use libcurl to HTTP PUT Xively如何使用 libcurl Xively HTTP PUT
【发布时间】:2014-10-13 23:06:34
【问题描述】:

我想发出 HTTPS PUT 请求来放置一个 csv 文件。下面是用于将数据上传到 Xively 的代码。早些时候我收到了 411 length required 错误。我参考了此处可用的代码 (Send string in PUT request with libcurl) 来解决此问题,其中创建了 CURLOPT_CUSTOMREQUEST。现在我收到 HTTP 500 内部服务器错误。

void upload()
{
   CURL *curl;
   CURLcode res;
   FILE * hd_src;
   struct stat file_info;
   struct curl_slist* header  = NULL;
   char * csvfile = "123.csv";

   /* get the file size */
   stat(csvfile, &file_info);

   hd_src = fopen("123.csv","rb");

   curl_global_init(CURL_GLOBAL_ALL);

   curl = curl_easy_init();

   if(curl)
   {

        header  = curl_slist_append(header,"X-ApiKey: 123123123"); /* API KEY HERE - sample only*/
        header = curl_slist_append(header,"Accept: text/csv");
        header = curl_slist_append(header, "Host: api.xively.com"); 

        curl_easy_setopt(curl, CURLOPT_HTTPHEADER, header);
        curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);

        /* Actual Xively feed  is here. For demonstration purpose the feed is listed as 123 */
        curl_easy_setopt(curl, CURLOPT_URL, "https://api.xively.com/v2/feeds/123.csv");

        curl_easy_setopt(curl, CURLOPT_READDATA, hd_src);
        curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, (curl_off_t)file_info.st_size);

        curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "PUT" );
        curl_easy_setopt(curl, CURLOPT_POSTFIELDS, hd_src);

        res = curl_easy_perform(curl); 

        if(res != CURLE_OK)
        {
            fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
        }
        curl_easy_cleanup(curl);        
   }
   fclose(hd_src);   
   curl_slist_free_all(header);
   curl_global_cleanup();
}

任何人都可以提出建议吗?如果我删除 curl_easy_setopt(curl, CURLOPT_POSTFIELDS, hd_src),我会得到 411 length required 错误。我删除了这个并使用 file_info.st_size 将 Content-Length 添加到标题中。再次收到 411 length required 错误。使用 curl_easy_setopt(curl, CURLOPT_POSTFIELDS, hd_src) 解决了 411 但 Xively 给出了 500 内部服务器错误。

提前致谢。

【问题讨论】:

    标签: linux http libcurl


    【解决方案1】:

    尝试改用CURLOPT_UPLOAD,就像documentation 所说的那样:

    CURLOPT_PUT - 发出 HTTP PUT 请求
    ...
    此选项自 7.12.1 版起已弃用。使用 CURLOPT_UPLOAD!

    CURLOPT_UPLOAD - 启用数据上传
    ...
    如果协议是 HTTP,上传意味着使用 PUT 请求,除非你告诉 libcurl 否则

    你必须非常小心CURLOPT_CUSTOMREQUEST

    CURLOPT_CUSTOMREQUEST - 请求的自定义字符串
    ...
    当您通过将 CURLOPT_CUSTOMREQUEST 设置为某个值来更改请求方法时,您实际上并没有改变 libcurl 对特定请求方法的行为或行为,它只会更改请求中发送的实际字符串
    ...
    许多人错误地使用此选项将整个请求替换为自己的请求,包括多个标头和 POST 内容。虽然这在许多情况下可能有效,但它会导致 libcurl 发送无效请求,并且可能会严重混淆远程服务器。

    您也没有发送Content-Type 标头,而是发送Accept 标头。 Content-Type 告诉服务器您要发送的数据类型。 Accept 告诉服务器你愿意收到什么类型的数据作为回复。

    最后,您没有对stat()fopen() 进行错误处理。

    试试这个:

    void upload()
    {
        CURL *curl;
        CURLcode res;
        FILE * hd_src;
        struct stat file_info = {0};
        struct curl_slist* header = NULL;
        char * csvfile = "C:\\full path to\\123.csv";
    
        /* get the file size */
        if (stat(csvfile, &file_info) == -1)
        {
            fprintf(stderr, "stat() failed: %s\n", strerror(errno));
            return;
        }
    
        hd_src = fopen(csvfile, "rb");
        if (!hd_src)
        {
            fprintf(stderr, "fopen() failed: %s\n", strerror(errno));
            return;
        }  
    
        curl_global_init(CURL_GLOBAL_ALL);
    
        curl = curl_easy_init();
        if (!curl)
        {
            fprintf(stderr, "curl_easy_init() failed\n");
        }
        else
        {
            header = curl_slist_append(header, "X-ApiKey: 123123123"); /* API KEY HERE - sample only*/
            header = curl_slist_append(header, "Content-Type: text/csv");
    
            curl_easy_setopt(curl, CURLOPT_HTTPHEADER, header);
            curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
    
            /* Actual Xively feed  is here. For demonstration purpose the feed is listed as 123 */
            curl_easy_setopt(curl, CURLOPT_URL, "https://api.xively.com/v2/feeds/123.csv");
    
            curl_easy_setopt(curl, CURLOPT_READDATA, hd_src);
            curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, (curl_off_t)file_info.st_size);
    
            curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L );
    
            res = curl_easy_perform(curl); 
            if (res != CURLE_OK)
                fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
    
            curl_slist_free_all(header);
            curl_easy_cleanup(curl);        
        }
    
        fclose(hd_src);   
    
        curl_global_cleanup();
    }
    

    【讨论】:

    • @ Remy,它成功了 - 谢谢。但是,现在我收到 413 Request Entity Too Large。我正在使用Linux机器。如果您有任何建议,请让我知道。谢谢。
    • 您要上传的文件有多大?
    • @Remy,它只有一行。我尝试了“ls -l”,系统显示 10 个字节。
    • 我唯一能想到的是如果stat() 失败,在file_info.st_size 中留下一个无效值,您将其按原样发送到服务器。您没有检查 stat()fopen() 是否失败。例如,您正在使用相对文件路径。尝试改用绝对路径。我更新了我的答案以表明这一点。
    • @Remy,我一直在使用绝对路径。在上面的代码中没有提到它。读取文件没有错误。我使用了您修改后的代码。同样的错误正在重复。好像当我使用 curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, (curl_off_t)file_info.st_size);尽管文件很小,但内容长度似乎任意大。我尝试通过禁用 CURLOPT_INFILESIZE_LARGE 并将内容长度字符串从 stat() 文件信息添加到标头并与文件大小匹配。然后抛出 411 错误。有什么建议么??谢谢。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-08-03
    • 2011-03-01
    • 1970-01-01
    • 2014-06-05
    • 2016-07-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多