JSON demande en C en utilisant libcurl

Je définit une requête PUT avec un corps de requête JSON en utilisant libcurl dans C.

comment je fais:

    sprintf(jsonObj, ""name" : "%s", "age" : "%s"", name, age);

    struct curl_slist *headers = NULL;
    curl_slist_append(headers, "Accept: application/json");
    curl_slist_append(headers, "Content-Type: application/json");
    curl_slist_append(headers, "charsets: utf-8");

    curl_easy_setopt(curl, CURLOPT_URL, url);

    curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "PUT");
    curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); 
    curl_easy_setopt(curl, CURLOPT_POSTFIELDS, jsonObj);
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&chunk);
    curl_easy_setopt(curl, CURLOPT_USERAGENT, "libcrp/0.1");

    res = curl_easy_perform(curl);

le corps de La requête est arrivée comme ceci:

    { '"name" : "Pedro", "age" : "22"' }

{ ' au début et ' } à la fin.

--- PLUS D'INFO -----

si je déclare ce code

    char* jsonObj = "{ "name" : "Pedro" , "age" : "22" }"; 

    struct curl_slist *headers = NULL;
    curl_slist_append(headers, "Accept: application/json");
    curl_slist_append(headers, "Content-Type: application/json");
    curl_slist_append(headers, "charsets: utf-8");

    curl_easy_setopt(curl, CURLOPT_URL, url);

    curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "PUT");
    curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); 
    curl_easy_setopt(curl, CURLOPT_POSTFIELDS, jsonObj);
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&chunk);
    curl_easy_setopt(curl, CURLOPT_USERAGENT, "libcrp/0.1");

    res = curl_easy_perform(curl);

le serveur reçoit ceci comme le corps de la requête:

{ '{ "name" : "Pedro" , "age" : "22" }': '' }

Ma question est:

est le libCurl pré-formatage / encodage automatique de la requête Json?

au fait, libCurl a-t-il un moyen d'encoder un objet JSON?

Merci beaucoup!

10
demandé sur Pedro Baptista Afonso 2012-08-15 21:21:26

6 réponses

Le problème peut être avec les en-têtes. Lorsque vous configurez vos en-têtes curl_slist, je pense que vous devriez affecter la sortie de curl_slist_append retour aux en-têtes:

struct curl_slist *headers = NULL;
headers = curl_slist_append(headers, "Accept: application/json");
headers = curl_slist_append(headers, "Content-Type: application/json");
headers = curl_slist_append(headers, "charsets: utf-8");
14
répondu JustinB 2012-10-17 16:14:32

tout d'abord, notons quelques choses. Pour commencer, Daniel Stenberg a raison (comme je l'espère, étant donné qu'il a écrit le code): libcurl n'ajoute aucune donnée à votre code. Je peux le démontrer avec cet exemple de programme, qui est comme votre exemple, mais avec une configuration supplémentaire/démontage de code. C'est le code: il n'y a rien d'autre ici présent:

#include <curl/curl.h>

int main (int argc, char *argv[]) {
    CURL *curl;
    CURLcode res;

    curl_global_init(CURL_GLOBAL_ALL);
    curl = curl_easy_init();
    if (curl == NULL) {
        return 128;
    }

    char* jsonObj = "{ \"name\" : \"Pedro\" , \"age\" : \"22\" }";

    struct curl_slist *headers = NULL;
    curl_slist_append(headers, "Accept: application/json");
    curl_slist_append(headers, "Content-Type: application/json");
    curl_slist_append(headers, "charsets: utf-8");

    curl_easy_setopt(curl, CURLOPT_URL, "http://http2bin.org/put");

    curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "PUT");
    curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
    curl_easy_setopt(curl, CURLOPT_POSTFIELDS, jsonObj);
    curl_easy_setopt(curl, CURLOPT_USERAGENT, "libcrp/0.1");

    res = curl_easy_perform(curl);

    curl_easy_cleanup(curl);
    curl_global_cleanup();
    return res;
}

la capture de paquet de la requête avec Wireshark montre que celle-ci émet les signaux suivants: HTTP request:

PUT /put HTTP/1.1
Host: http2bin.org
User-Agent: libcrp/0.1
Accept: */*
Content-Length: 35
Content-Type: application/x-www-form-urlencoded

{ "name" : "Pedro" , "age" : "22" }

comme vous pouvez le voir, ce sont exactement les données JSON que vous avez demandé d'envoyer. Il n'y a pas de données supplémentaires ici, pas d'attaches.

Cela signifie que les accolades supplémentaires sont ajoutées, soit par votre serveur ou par l'intermédiaire middlebox. Mon avis est que votre serveur l'ajoute parce qu'il essaye de tourner de force n'importe quel corps qui n'est pas un application/json corps en un en considérant le corps entier comme une ficelle.

La raison votre serveur ne considère pas que C'est un corps JSON est encapsulé par une autre réponse ici: vous ne paramétrez pas vos en-têtes correctement. curl_slist_appendretourne un nouveau struct curl_slist * que vous devez assigner de nouveau dans votre headers variable. Cela signifie que vous devez changer ces quatre lignes:

struct curl_slist *headers = NULL;
curl_slist_append(headers, "Accept: application/json");
curl_slist_append(headers, "Content-Type: application/json");
curl_slist_append(headers, "charsets: utf-8");

pour ces quatre:

struct curl_slist *headers = NULL;
headers = curl_slist_append(headers, "Accept: application/json");
headers = curl_slist_append(headers, "Content-Type: application/json");
headers = curl_slist_append(headers, "charsets: utf-8");

cela devrait convaincre votre serveur que vous envoyez des données JSON.

Dans l'avenir, je vous recommande de vous familiariser avec Wireshark pour résoudre ce type de problèmes. Il est extrêmement utile de voir la demande réelle que vous avez envoyé. Sinon, si vous ne voulez pas, vous pouvez utiliser CURLOPT_DEBUGFUNCTION pour saisir les données que curl envoie pour les valider.

13
répondu Lukasa 2017-01-18 08:24:16

libcurl enverra exactement les octets de vous demander d'envoyer. Il n'a pas connaissance de JSON.

voir la réponse excellente et plus élaborée de @Lukasa pour de meilleurs et plus de détails.

3
répondu Daniel Stenberg 2017-01-18 08:27:56

j'avais un problème similaire.

j'ai découvert l'option-libcurl pour la commande curl. Il a beaucoup aidé! Il suffit de l'ajouter à la fin de votre commande curl.

À la fin il m'aider à créer ce code:

  CURLcode ret;
  CURL *hnd;
  struct curl_slist *slist1;
  std::string jsonstr = "{\"username\":\"bob\",\"password\":\"12345\"}";

  slist1 = NULL;
  slist1 = curl_slist_append(slist1, "Content-Type: application/json");

  hnd = curl_easy_init();
  curl_easy_setopt(hnd, CURLOPT_URL, "http://u/r/l");
  curl_easy_setopt(hnd, CURLOPT_NOPROGRESS, 1L);
  curl_easy_setopt(hnd, CURLOPT_POSTFIELDS, jsonstr.c_str());
  curl_easy_setopt(hnd, CURLOPT_USERAGENT, "curl/7.38.0");
  curl_easy_setopt(hnd, CURLOPT_HTTPHEADER, slist1);
  curl_easy_setopt(hnd, CURLOPT_MAXREDIRS, 50L);
  curl_easy_setopt(hnd, CURLOPT_CUSTOMREQUEST, "POST");
  curl_easy_setopt(hnd, CURLOPT_TCP_KEEPALIVE, 1L);

  ret = curl_easy_perform(hnd);

  curl_easy_cleanup(hnd);
  hnd = NULL;
  curl_slist_free_all(slist1);
  slist1 = NULL;

Express reçoit JSON:

{ username: 'bob', password: '12345' }

j'espère que cela aide!

2
répondu Canadian_Republican 2016-05-02 15:51:13

un élément clé pour comprendre si le système se comporte correctement est de voir ce que le programme envoie réellement sur le réseau. Donc une autre façon de vérifier le flux d'octets, au lieu de le pointer vers votre serveur (et/ou lancer Wireshark), est de lancer un netcat instance dans une fenêtre séparée sur la machine test:

nc -l 8080

et pointer le code (CURLOPT_URL) à"http://localhost:8080".

Vous aurez besoin de frapper Contrôle-D dans le nc fenêtre pour terminer la connexion de sorte que curl complète, mais vous pouvez également taper un texte de retour de test à l'avance, ce qui peut être utile si vous attendez une sorte de réponse pour tester contre.

1
répondu Pierz 2017-07-07 12:28:10

j'ai utilisé json-c pour encoder et décoder jsons et ça a très bien marché. La documentation est également facile à comprendre. https://linuxprograms.wordpress.com/2010/05/20/json-c-libjson-tutorial/

-2
répondu Jonny_Pony 2016-10-26 08:57:20