2015-04-21 15 views
209

Ich versuche, ein JSON-Objekt mit fetch POST.Fetch: POST JSON-Daten

Von dem, was ich verstehen kann, ich brauche, um den Körper des Antrags ein Zeichenfolge Objekt zu befestigen, zum Beispiel:

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) }) 

Wenn jsfiddle's json echo verwenden würde ich erwarten, dass das Objekt zu sehen, ich geschickt habe ({a: 1, b: 2}) zurück, aber das passiert nicht - chrome devtools zeigt JSON nicht einmal als Teil der Anfrage an, was bedeutet, dass es nicht gesendet wird.

+0

Welche Browser verwenden Sie? –

+0

@KrzysztofSafjanowski Chrome 42, die [Full-Fetch-Unterstützung] haben soll (http://caniuse.com/#search=fetch) – Razor

+0

überprüfen Sie diese Geige https://jsfiddle.net/abbpbah4/2/ welche Daten Sie ' erwartest du? weil die Anfrage von https://fiddle.jshell.net/echo/json ein leeres Objekt anzeigt. '{}' –

Antwort

137

Chrom devtools nicht einmal

Diese JSON als Teil des Antrags zeigen, ist die echtes Problem hier, und es ist ein bug with chrome devtools, in Chrome 46 behoben.

Dieser Code funktioniert gut - es ist POSTing der JSON korrekt, es kann einfach nicht gesehen werden.

Ich würde erwarten, dass das Objekt zu sehen, ich

zurückgeschickt habe, die Arbeit nicht, weil das nicht die correct format for JSfiddle's echo ist.

Die correct code ist:

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)) }) 

Für Endpunkte JSON Nutzlasten zu akzeptieren, der ursprüngliche Code

+7

Für die Aufzeichnung, dies ist nicht ein JSON-Payload - das ist ein Formular Post ('x-www-Form-urlencoded') mit einem JSON-Daten in einem Feld mit dem Namen' json'. Die Daten sind also doppelt kodiert. Für einen sauberen JSON-Post, siehe Antwort von @vp_arth unten. –

24

Nach einigen Zeiten, Reverse-Engineering jsFiddle, versuchen, Payload zu generieren - es gibt einen Effekt.

Bitte beachten Sie (Pflege) auf Linie return response.json();, wo Antwort ist keine Antwort - es ist Versprechen.

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

+0

Warum "x-www-form-urlencoded" statt "application/json"? Was ist der Unterschied? –

+0

@JuanPicado - nach ** jsfiddle ** Reverse Engineering vor 2 Jahren war es nur eine Möglichkeit, dass es funktionieren konnte. Natürlich ist "application/json" die richtige Form und es funktioniert jetzt. Danke für das gute Auge:) –

+0

yw. Neugieriges Detail, es funktioniert bei mir auf die alte Art mit 'fetch' (http://stackoverflow.com/questions/41984893/fetch-post-fails-on-post-json-body-with-sails-js?noredirect = 1 # comment71171442_41984893) stattdessen die 'application/json'. Vielleicht weißt du warum ... –

24

Von Suchmaschinen korrekt ist, endete ich für nicht-json Buchungsdaten zu diesem Thema nach oben mit holen , dachte ich, würde ich das hinzufügen.

Für non-json müssen Sie keine Formulardaten verwenden. Sie können einfach den Content-Type Header application/x-www-form-urlencoded gesetzt und eine Zeichenfolge verwenden:

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' 
}); 

Ein alternativer Weg zu bauen, dass body String, sondern tippen sie dann, wie ich oben tat, ist Bibliotheken zu verwenden. Zum Beispiel die stringify Funktion von query-string oder qs Pakete. Also das mit, es würde wie folgt aussehen:

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} 
}); 
+1

Vielen Dank für Query String, ich habe so oft mit JSON.Stringify versucht, aber AJAX hat keine Antwort zurückgegeben. aber Query String hat den Trick gemacht. Ich fand auch, dass es war, weil fetch json für body params erstellt, anstatt eine Zeichenkette zu erstellen. – Danish

+1

Danke Mann! Das ist die beste Antwort! Ich war gestern für ein paar Stunden an der Wand und versuchte einen Weg zu finden, wie man "Körper" mit Formulardaten von meiner Webanwendung an meinen Server senden kann ... Ein Vorschlag: $ npm install cors --save Dies wird benötigt, um loszuwerden " Modus: 'No-Cors' "in Abrufanforderung siehe https://github.com/expressjs/cors –

+0

Dank @AlexanderCherednichenko! Und danke, dass ihr diese Corss-Notiz geteilt habt, dass ist eine interessante, von der ich nichts wusste. :) – Noitidart

94

Ich denke, Ihr Problem jsfiddle ist nur form-urlencoded Anfrage bearbeiten kann.

Aber richtiger Weg json Antrag zu stellen ist richtig json als Körper passiert:

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));

+2

tnx. korrekte Lösung in asp.net mvc. –

+2

Dies ist die richtige Lösung, _period_ - alle anderen scheinen mit 'x-www-form-urlencoded' vs.' application/json' verwechselt zu werden, entweder nicht übereinstimmend oder JSON mit Doppelumbruch in URL-codierten Strings. –

10

ich um eine dünne Hülle geschaffen habe() mit vielen Verbesserungen holen, wenn Sie eine verwenden rein json REST API:

// 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); 
}); 

es nutzen zu können, müssen Sie die VariableVerfahren 0 und 4:

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

und innerhalb einer async Funktion:

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

Beispiel mit 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'); 
}); 
+0

Ich glaube, du meintest einen anderen Satz von Argumenten für 'Object.assign'? sollte 'Object.assign ({}, api.headers, headers)' sein, weil Sie nicht weiterhin benutzerdefinierte 'headers' im Hash von 'api.headers' hinzufügen wollen. Recht? – Mobigital

+0

@Mobigital völlig richtig, ich wusste nicht über diese Nuance damals, aber jetzt ist es die einzige Art, wie ich es mache –

3

Dies wird Content-Type verwendet. Wie Sie vielleicht aus anderen Diskussionen und Antworten auf diese Frage bemerkt haben, konnten einige Leute es lösen, indem sie Content-Type: 'application/json' setzten. Leider funktionierte es in meinem Fall nicht, meine POST-Anfrage war auf der Serverseite immer noch leer.

Wenn Sie jedoch mit $.post() von jQuery versuchen und es funktioniert, liegt der Grund wahrscheinlich an jQuery mit Content-Type: 'x-www-form-urlencoded' anstelle von 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'} 
}) 
+0

Mein Backend-Entwickler baute die API mit PHP aus, erwartete die Daten Abfrage-String wie, kein JSON-Objekt . Dies löste die leere Antwort auf der Serverseite. – eballeste

6

haben das gleiche Problem - keine body von einem Client an einen Server gesendet wurde.

Hinzufügen Content-Type Kopf gelöst es für mich:

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 => { 
    ... 
})