web-dev-qa-db-fra.com

Récupérer: POST json data

J'essaie de POST un objet JSON à l'aide de fetch .

D'après ce que je peux comprendre, je dois attacher un objet sous forme de chaîne au corps de la demande, par exemple:

fetch("/echo/json/",
{
    headers: {
      'Accept': 'application/json',
      'Content-Type': 'application/json'
    },
    method: "POST",
    body: JSON.stringify({a: 1, b: 2})
})
.then(function(res){ console.log(res) })
.catch(function(res){ console.log(res) })

Lors de l'utilisation de json echo de jsfiddle , je m'attendrais à voir l'objet que j'ai envoyé ({a: 1, b: 2}), mais cela ne se produit pas - chrome devtools ne même montrer le JSON dans le cadre de la demande, ce qui signifie qu'il n'est pas envoyé.

424
Razor

Avec ES2017 async/await support , voici comment POST une charge JSON:

(async () => {
  const rawResponse = await fetch('https://httpbin.org/post', {
    method: 'POST',
    headers: {
      'Accept': 'application/json',
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({a: 1, b: 'Textual content'})
  });
  const content = await rawResponse.json();

  console.log(content);
})();

Vous ne pouvez pas utiliser ES2017? Voir @ vp_art's répondre en utilisant des promesses

La question cependant demande un problème causé par depuis longtemps un bug corrigé chrome.
La réponse originale suit.

chrome devtools ne montre même pas le JSON dans le cadre de la demande

C'est le vrai problème ici , et c'est un bug avec chrome devtools , corrigé dans Chrome 46.

Ce code fonctionne bien - il poste correctement le JSON, il ne peut tout simplement pas être vu.

Je m'attendrais à voir l'objet que j'ai renvoyé

ça ne marche pas parce que ce n'est pas le format correct pour l'écho de JSfiddle .

Le code correct est:

var payload = {
    a: 1,
    b: 2
};

var data = new FormData();
data.append( "json", JSON.stringify( payload ) );

fetch("/echo/json/",
{
    method: "POST",
    body: data
})
.then(function(res){ return res.json(); })
.then(function(data){ alert( JSON.stringify( data ) ) })

Pour les systèmes d'extrémité acceptant les charges JSON, , le code d'origine est correct

427
Razor

Je pense que votre problème est que jsfiddle ne peut traiter que form-urlencoded demande uniquement.

Mais la bonne façon de faire une requête json est de passer correctement json en tant que corps:

fetch('https://httpbin.org/post', {
  method: 'post',
  headers: {
    'Accept': 'application/json, text/plain, */*',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({a: 7, str: 'Some string: &=&'})
}).then(res=>res.json())
  .then(res => console.log(res));
171
vp_arth

Des moteurs de recherche, je me suis retrouvé sur ce sujet pour les données postées non-json avec fetch, donc je pensais ajouter ceci.

Pour non-json , vous n'êtes pas obligé d'utiliser les données de formulaire. Vous pouvez simplement définir l'en-tête _Content-Type_ sur _application/x-www-form-urlencoded_ et utiliser une chaîne:

_fetch('url here', {
    method: 'POST',
    headers: {'Content-Type':'application/x-www-form-urlencoded'}, // this line is important, if this content-type is not set it wont work
    body: 'foo=bar&blah=1'
});
_

Une autre façon de construire cette chaîne body, plutôt que de la taper comme je l'ai fait ci-dessus, consiste à utiliser des bibliothèques. Par exemple, la fonction stringify de query-string ou qs packages. Donc, en utilisant ceci, cela ressemblerait à:

_import queryString from 'query-string';
fetch('url here', {
    method: 'POST',
    headers: {'Content-Type':'application/x-www-form-urlencoded'}, // this line is important, if this content-type is not set it wont work
    body: queryString.stringify({for:'bar', blah:1}
});
_
42
Noitidart

Après avoir passé du temps à l’ingénierie inverse, jsFiddle essaie de générer une charge utile - il y a un effet.

S'il vous plaît prenez les yeux sur la ligne return response.json(); où la réponse n'est pas une réponse - c'est une promesse.

var json = {
    json: JSON.stringify({
        a: 1,
        b: 2
    }),
    delay: 3
};

fetch('/echo/json/', {
    method: 'post',
    headers: {
        'Accept': 'application/json, text/plain, */*',
        'Content-Type': 'application/json'
    },
    body: 'json=' + encodeURIComponent(JSON.stringify(json.json)) + '&delay=' + json.delay
})
.then(function (response) {
    return response.json();
})
.then(function (result) {
    alert(result);
})
.catch (function (error) {
    console.log('Request failed', error);
});

jsFiddle: http://jsfiddle.net/egxt6cpz/46/ && Firefox> 39 && Chrome> 42

35

J'ai créé un wrapper fin autour de fetch () avec de nombreuses améliorations si vous utilisez une API purement json REST:

// Small library to improve on fetch() usage
const api = function(method, url, data, headers = {}){
  return fetch(url, {
    method: method.toUpperCase(),
    body: JSON.stringify(data),  // send it as stringified json
    credentials: api.credentials,  // to keep the session on the request
    headers: Object.assign({}, api.headers, headers)  // extend the headers
  }).then(res => res.ok ? res.json() : Promise.reject(res));
};

// Defaults that can be globally overwritten
api.credentials = 'include';
api.headers = {
  'csrf-token': window.csrf || '',    // only if globally set, otherwise ignored
  'Accept': 'application/json',       // receive json
  'Content-Type': 'application/json'  // send json
};

// Convenient methods
['get', 'post', 'put', 'delete'].forEach(method => {
  api[method] = api.bind(null, method);
});

Pour l'utiliser, vous avez la variable api et 4 méthodes:

api.get('/todo').then(all => { /* ... */ });

Et dans une fonction async:

const all = await api.get('/todo');
// ...

Exemple avec jQuery:

$('.like').on('click', async e => {
  const id = 123;  // Get it however it is better suited

  await api.put(`/like/${id}`, { like: true });

  // Whatever:
  $(e.target).addClass('active dislike').removeClass('like');
});
16
Francisco Presencia

Avait le même problème - pas body a été envoyé à partir d'un client à un serveur.

L'ajout de l'en-tête Content-Type l'a résolu pour moi:

var headers = new Headers();

headers.append('Accept', 'application/json'); // This one is enough for GET requests
headers.append('Content-Type', 'application/json'); // This one sends body

return fetch('/some/endpoint', {
    method: 'POST',
    mode: 'same-Origin',
    credentials: 'include',
    redirect: 'follow',
    headers: headers,
    body: JSON.stringify({
        name: 'John',
        surname: 'Doe'
    }),
}).then(resp => {
    ...
}).catch(err => {
   ...
})
11
Green

Ceci est lié à Content-Type. Comme vous l'avez peut-être remarqué lors d'autres discussions et réponses à cette question, certaines personnes ont pu résoudre le problème en définissant Content-Type: 'application/json'. Malheureusement, dans mon cas, cela ne fonctionnait pas, ma demande POST était toujours vide du côté serveur.

Cependant, si vous essayez avec $.post() de jQuery et que cela fonctionne, la raison en est probablement due au fait que jQuery utilise Content-Type: 'x-www-form-urlencoded' au lieu de application/json.

data = Object.keys(data).map(key => encodeURIComponent(key) + '=' + encodeURIComponent(data[key])).join('&')
fetch('/api/', {
    method: 'post', 
    credentials: "include", 
    body: data, 
    headers: {'Content-Type': 'application/x-www-form-urlencoded'}
})
10
Marcus Lind

La première réponse ne fonctionne pas pour PHP7, car le codage est incorrect, mais je peux trouver le bon codage avec les autres réponses. Ce code envoie également des cookies d’authentification, ce que vous souhaiterez probablement, par exemple. PHP forums:

Julia = function(juliacode) {
    fetch('Julia.php', {
        method: "POST",
        credentials: "include", // send cookies
        headers: {
            'Accept': 'application/json, text/plain, */*',
            //'Content-Type': 'application/json'
            "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8" // otherwise $_POST is empty
        },
        body: "juliacode=" + encodeURIComponent(juliacode)
    })
    .then(function(response) {
        return response.json(); // .text();
    })
    .then(function(myJson) {
        console.log(myJson);
    });
}
4
lama12345

Cela pourrait être utile à quelqu'un:

J'avais le problème que formdata n'était pas envoyé pour ma demande

Dans mon cas, il s'agissait d'une combinaison d'en-têtes suivants qui étaient également à l'origine du problème et du type de contenu incorrect.

J'envoyais donc ces deux en-têtes avec la demande et ce n'était pas l'envoi des données de formulaire lorsque j'ai supprimé les en-têtes qui fonctionnaient.

"X-Prototype-Version" : "1.6.1",
"X-Requested-With" : "XMLHttpRequest"

De même que d'autres réponses suggèrent que l'en-tête Content-Type doit être correct.

Pour ma demande l'en-tête Content-Type correct était:

"Content-Type": "application/x-www-form-urlencoded; charset = UTF-8"

Ainsi, si vos données de formulaire ne sont pas attachées à la demande, il pourrait s'agir de vos en-têtes. Essayez de minimiser vos en-têtes, puis essayez de les ajouter un par un pour voir si votre problème est résolu.

3
user_CC

Si votre charge JSON contient des tableaux et des objets imbriqués, j'utiliserais la méthode URLSearchParams et la méthode param() de jQuery.

fetch('/somewhere', {
  method: 'POST',
  body: new URLSearchParams($.param(payload))
})

Pour votre serveur, cela ressemblera à un fichier HTML standard <form> étant POSTed.

3
Eric Sellin