使用C的原始libcurl JSON PUT请求

我目前正在编写类似REST的客户端,只需要执行PUT请求。

问题:
运行程序并没有在URL的API上给我正确的结果,我不知道为什么。

使用curl_easy_perform(curl)不会在调用时抛出错误。 但是,不会在URL的API上生成预期结果。

使用curl_easy_send(curl,..,..,..)会抛出:不支持的协议错误

假设:
我假设我使用curl_easy_opts的顺序是个问题? 我甚至错过了几个关键线?

我一直在这里阅读其他人如何做PUT请求并一直在使用他们的方法。

计划摘要:

我的程序提示用户输入一些字符串/字符数据,从中我自己构造字符串,例如标题和有效负载。 标头和有效负载都是JSON格式,但有效负载只是一个字符串(在这种情况下,char * str =(char *)mallo …等)。 标题的构造方式如下所示。

我的标题正在使用

struct curl_slist *headers = NULL; headers = curl_slist_append(headers, "Accept: application/json"); //there is more content being appended to the header 

CURL函数调用:

  //init winsock stuff curl_global_init(CURL_GLOBAL_ALL); //get a curl handle curl = curl_easy_init(); if(curl){ //append the headers curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); //specify the target URL curl_easy_setopt(curl, CURLOPT_URL, url); //connect ( //i added this here since curl_easy_send() says it requires it. ) curl_easy_setopt(curl, CURLOPT_CONNECT_ONLY,1L); //specify the request (PUT in our case) curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "PUT"); //append the payload curl_easy_setopt(curl, CURLOPT_POSTFIELDS, payload); res = curl_easy_perform(curl); //res = curl_easy_send(curl, payload, strlen(payload),&iolen); //check for errors if(res != CURLE_OK) fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res)); curl_easy_cleanup(curl); } 

您不应该使用CURLOPT_CONNECT_ONLY选项或curl_easy_send()函数,这些函数旨在用于自定义的非HTTP协议。

有关如何使用libcurl执行PUT请求的示例,请参阅此页面 。 基本上,您希望启用CURLOPT_UPLOADCURLOPT_PUT选项来表示您正在执行PUT请求并启用上传请求的正文,然后设置CURLOPT_READDATACURLOPT_INFILESIZE_LARGE选项以告诉libcurl如何读取您的数据重新上传以及数据有多大。

在你的情况下,如果你已经在内存中有数据,那么你不需要从文件中读取它,你可以在你的读回调中memcpy()它。

下面复制的示例代码:

 /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2012, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at http://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ #include  #include  #include  #include  /* * This example shows a HTTP PUT operation. PUTs a file given as a command * line argument to the URL also given on the command line. * * This example also uses its own read callback. * * Here's an article on how to setup a PUT handler for Apache: * http://www.apacheweek.com/features/put */ static size_t read_callback(void *ptr, size_t size, size_t nmemb, void *stream) { size_t retcode; curl_off_t nread; /* in real-world cases, this would probably get this data differently as this fread() stuff is exactly what the library already would do by default internally */ retcode = fread(ptr, size, nmemb, stream); nread = (curl_off_t)retcode; fprintf(stderr, "*** We read %" CURL_FORMAT_CURL_OFF_T " bytes from file\n", nread); return retcode; } int main(int argc, char **argv) { CURL *curl; CURLcode res; FILE * hd_src ; struct stat file_info; char *file; char *url; if(argc < 3) return 1; file= argv[1]; url = argv[2]; /* get the file size of the local file */ stat(file, &file_info); /* get a FILE * of the same file, could also be made with fdopen() from the previous descriptor, but hey this is just an example! */ hd_src = fopen(file, "rb"); /* In windows, this will init the winsock stuff */ curl_global_init(CURL_GLOBAL_ALL); /* get a curl handle */ curl = curl_easy_init(); if(curl) { /* we want to use our own read function */ curl_easy_setopt(curl, CURLOPT_READFUNCTION, read_callback); /* enable uploading */ curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L); /* HTTP PUT please */ curl_easy_setopt(curl, CURLOPT_PUT, 1L); /* specify target URL, and note that this URL should include a file name, not only a directory */ curl_easy_setopt(curl, CURLOPT_URL, url); /* now specify which file to upload */ curl_easy_setopt(curl, CURLOPT_READDATA, hd_src); /* provide the size of the upload, we specicially typecast the value to curl_off_t since we must be sure to use the correct data size */ curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, (curl_off_t)file_info.st_size); /* Now run off and do what you've been told! */ res = curl_easy_perform(curl); /* Check for errors */ if(res != CURLE_OK) fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res)); /* always cleanup */ curl_easy_cleanup(curl); } fclose(hd_src); /* close the local file */ curl_global_cleanup(); return 0; } 

我同意,不要使用CUSTOMREQUEST。 我在这里看到的每一个与PUT和CURL相关的细节都是你需要设置文件大小,否则你会得到HTTP错误411.使用CURLOPT_INFILESIZE或CURLOPT_INFILESIZE_LARGE。 在这里查看更多细节:

如何在不使用文件指针的情况下在libcurl中发送长PUT数据?