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é.
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
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));
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}
});
_
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
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');
});
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 => {
...
})
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'}
})
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);
});
}
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.
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 POST
ed.