繁体   English   中英

使用C的原始libcurl JSON PUT请求

[英]a raw libcurl JSON PUT request using C

我目前正在编写类似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, <daniel@haxx.se>, 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 <stdio.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <curl/curl.h>

/*
 * 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数据?

我知道这是一个非常古老的问题,但是如果有人想使用带有GLib和json-glib的libcurl来发送带有PUT请求的JSON。 以下代码对我有用:

    #include <curl/curl.h>
    #include <json-glib/json-glib.h>

    //this is callback function for CURLOPT_READFUNCTION: 

    static size_t
    curlPutJson ( void *ptr, size_t size, size_t nmemb, void *_putData )
    {
            GString *putData = ( GString * ) _putData;
            size_t realsize = ( size_t ) putData->len;
            memcpy ( ptr, putData->str, realsize );
            return realsize;
    }

   /*now inside main or other function*/

   //json_to_string ( jsonNode, FALSE ) is from json-glib to stringify JSON
   //created in jsonNode

   GString *putData = g_string_new ( json_to_string ( mainNode, FALSE ) );

   //now goes curl as usual: headers, url, other options and so on
   //and 4 most important lines

   curl_easy_setopt ( curl, CURLOPT_READFUNCTION, curlPutJson );
   curl_easy_setopt ( curl, CURLOPT_UPLOAD, 1L );

   curl_easy_setopt ( curl, CURLOPT_READDATA, putData );        //GString
   curl_easy_setopt ( curl, CURLOPT_INFILESIZE, putData->len ); //type long     

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM