Getirme: POST json verileri


562

Getirme kullanarak bir JSON nesnesi POST çalışıyorum .

Ne anlayabiliyorum, örneğin, istek gövdesine dizgi nesneyi eklemek gerekir:

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

Jsfiddle'ın json echo'unu kullanırken {a: 1, b: 2}geri gönderdiğim nesneyi görmeyi beklerdim ( ), ancak bu gerçekleşmez - krom devtools, JSON'u isteğin bir parçası olarak göstermez, yani gönderilmez.


Hangi tarayıcıyı kullanıyorsunuz?
Krzysztof Safjanowski


bu keman jsfiddle.net/abbpbah4/2 hangi verileri beklediğinizi kontrol edin ? çünkü get fiddle.jshell.net/echo/json isteği boş nesne gösteriyor. {}
Kaushik

@KaushikKishore beklenen çıktıyı açıklığa kavuşturmak için düzenlendi. res.json()dönmelidir {a: 1, b: 2}.
Razor

1
jsonGöndermek istediğiniz verileri içeren mülkü eklemeyi unuttunuz . Ancak, ben bodyzaten doğru tedavi edilmiyor. 5 saniyelik gecikmenin atlandığını görmek için bu kemanı görün. jsfiddle.net/99arsnkg Ayrıca, ek başlıklar eklemeye çalıştığınızda yok sayılırlar. Bu muhtemelen fetch()kendisiyle ilgili bir konudur .
boombox

Yanıtlar:


598

ES2017 ile async/awaitdestek , bu nasıl olduğunu POSTbir JSON yük:

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

ES2017'yi kullanamıyor musunuz? @ Vp_art'ın vaatleri kullanarak verdiği cevaba bakınız

Ancak soru, uzun süredir sabit olan bir krom hatasının neden olduğu bir sorun istiyor .
Orijinal cevap aşağıdadır.

chrome devtools, JSON'u isteğin bir parçası olarak göstermiyor

Buradaki gerçek sorun ve Chrome 46'da düzeltilen krom cihazlarında bir hata .

Bu kod iyi çalışıyor - JSON'u doğru şekilde GÖSTERİYOR, sadece görülemiyor.

Geri gönderdiğim nesneyi görmeyi beklerdim

bu çalışmıyor çünkü JSfiddle'ın yankısı için doğru format bu değil .

Doğru kod geçerli:

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

JSON yüklerini kabul eden uç noktalar için orijinal kod doğrudur


15
Kayıt için bu bir JSON yükü göndermez - bu, x-www-form-urlencodedadlı bir alanda JSON verisi olan bir form gönderisidir ( ) json. Böylece veriler iki kez kodlanır. Temiz bir JSON yayını için aşağıdaki @vp_arth tarafından verilen cevaba bakın.
mindplay.dk

1
@ mindplay.dk Bu bir x-www-form-urlencoded yazı değildir. Getirme API'si FormData nesnelerinde her zaman çok bölümlü / form-veri kodlaması kullanır.
JukkaP

@JukkaP Ben düzeltilmiş duruyorum. Ana nokta, çift kodlama sorunu oldu.
mindplay.dk

2
İçerik Türü hala metin / html'dir; charset = iso-8859-1 yanlış yaptığımı bilmiyorum ...
KT Works

3
Güvenli tarafta olmak için res.ok, yanıt kodunun bir tür hata olması durumunda onaylamak iyi olur . Sonunda bir .catch()fıkra olması da iyi olur . Bunun sadece örnek bir snippet olduğunu anlıyorum, ancak gerçek dünya kullanımı için bunları aklınızda bulundurun.
Ken Lyon

206

Sorununuzun yalnızca isteği jsfiddleişleyebileceğini düşünüyorum form-urlencoded.

Ancak json isteği yapmanın doğru yolu json, bir vücut olarak doğru geçmek :

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


6
Bu doğru çözümdür, dönem - herkes x-www-form-urlencodedvs vs ile karıştırılmış gibi görünüyor application/json, ya onları eşleştirmiyor ya da url kodlu dizelerde JSON'u çift sarıyor.
mindplay.dk

Ama bu jsfiddle için işe yaramıyor. Bu yüzden, neden "Bu doğru çözüm, dönem" diyeceğinizi anladığımdan emin değilim. Herkes jsfiddle'ın /echorotasının API'sını karşılamak için ambalajı yapmıyor mu?
adam-beck

69

Arama motorlarından, getirme ile json olmayan veri gönderme için bu konuda sona erdi, bu yüzden bunu ekleyeceğini düşündüm.

For olmayan json form verilerini kullanmak gerekmez. Content-TypeÜstbilgiyi yalnızca application/x-www-form-urlencodedbir dize olarak ayarlayabilir ve kullanabilirsiniz:

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

Bu bodydizeyi oluşturmanın alternatif bir yolu , daha önce yaptığım gibi yazmak yerine, kütüphaneleri kullanmaktır. Örneğin, stringifyişlev query-stringveya qspaketlerden. Yani bunu kullanarak şöyle görünecektir:

import queryString from 'query-string'; // import the queryString class

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}) //use the stringify object of the queryString class
});

2
sorgu dizesi için çok teşekkür ederim, JSON.stringify ile birçok kez denedim ama ajax yanıt döndürmüyordu. ancak sorgu dizesi hile yaptı. Ben de çünkü getirme dize oluşturmak yerine vücut params için json oluşturmak olduğunu bulundu.
Danimarka

1
Teşekkür ederim dostum! Bu en iyi cevap! Dün birkaç saat boyunca duvara çarpıyordum, web uygulamamdan form verileriyle "gövde" yi sunucuma göndermek için bir yol bulmaya çalışıyordum ... Bir öneri: $ npm install cors --save Bu kurtulmak için gerekli " modu: "No-cors" "Fetch isteğinde bkz. github.com/expressjs/cors
Alexander Cherednichenko

Teşekkürler @AlexanderCherednichenko! Ve paylaştığınız için teşekkürler cors not bilmediğim ilginç bir şey. :)
Noitidart

1
Kalbimin derinliklerinden teşekkürler. Zamanımı ve ayrıca hayatımı iki kez kurtardın :)
bafsar

1
Thnaks @bafsar!
Noitidart

42

Bazı zamanlar harcadıktan sonra, ters yük jsFiddle, yükü oluşturmaya çalışıyor - bir etkisi var.

Lütfen return response.json();yanıtın yanıt olmadığı bir yere dikkat edin (dikkat) - söz veriyorum.

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 ve& Chrome> 42


Bunun 'x-www-form-urlencodedyerine neden application/json? Fark ne?
Juan Picado

@JuanPicado - jsfiddle tersine mühendislikten 2 yıl önce çalışabilmesi için sadece bir seçenek vardı. Tabii ki application/jsondoğru form ve şimdi çalışıyor. İyi göz için teşekkürler
:)

yw. Meraklı detay, benim için eski şekilde çalışıyor fetch( stackoverflow.com/questions/41984893/… ) yerine application/json. Belki de nedenini biliyorsun ...
Juan Picado

6
Content-TypeOlduğu application/json, ancak gerçek bodygörünür olmak x-www-form-urlencoded- Ben bu işe gerektiğini sanmıyorum? Çalışırsa, sunucunuz oldukça bağışlayıcı olmalıdır. Aşağıdaki @vp_arth tarafından verilen cevap doğru gibi görünüyor.
mindplay.dk

18

Tamamen json REST API kullanıyorsanız fetch () etrafında birçok iyileştirme ile ince bir sarmalayıcı oluşturduk:

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

Kullanmak için değişken apive 4 yöntem var:

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

Ve bir asyncfonksiyon içinde :

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

JQuery ile örnek:

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

Sanırım farklı bir argüman kümesi mi demek istediniz Object.assign? ortak hash içine Object.assign({}, api.headers, headers)özel eklemek istemiyorum çünkü olmalıdır . sağ? headersapi.headers
Mart'ta Mobigital

@Mobigital tamamen doğru, o nüansı o zaman bilmiyordum ama şimdi bunu yapmanın tek yolu
Francisco Presencia

11

Bu ile ilgilidir Content-Type. Diğer tartışmalardan ve bu sorunun yanıtlarından fark etmiş olabileceğiniz gibi, bazı insanlar bunu ayarlayarak çözebildiler Content-Type: 'application/json'. Ne yazık ki benim durumumda işe yaramadı, POST isteğim sunucu tarafında hala boştu.

Ancak, jQuery's ile denerseniz $.post()ve çalışıyorsa, bunun nedeni büyük olasılıkla Content-Type: 'x-www-form-urlencoded'yerine jQuery kullanmaktır 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'}
})

1
Benim arka uç geliştirici API ile PHP inşa, veri json nesnesi değil, sorgu dizesi olmasını bekliyordum. Bu, sunucu tarafındaki boş yanıtı çözdü.
eballeste

11

Aynı sorun vardı - bodybir istemciden bir sunucuya hayır gönderildi.

Content-TypeBaşlık eklemek benim için çözdü:

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

7

En iyi cevap PHP7 için çalışmıyor, çünkü yanlış kodlama var, ancak diğer cevaplarla doğru kodlamayı anlayabilirim. Bu kod aynı zamanda, örneğin PHP forumlarıyla uğraşırken muhtemelen istediğiniz kimlik doğrulama çerezlerini de gönderir:

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

3

Birisi için yararlı olabilir:

Form verilerimin isteğim için gönderilmemesi sorununu yaşıyordum

Benim durumumda, soruna ve yanlış İçerik Türü'ne neden olan aşağıdaki başlıkların bir birleşimi oldu.

Bu nedenle, bu iki üstbilgiyi istekle gönderiyordum ve çalışan üstbilgileri kaldırdığımda form verilerini göndermiyordu.

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

Ayrıca diğer yanıtlar İçerik Türü başlığının doğru olması gerektiğini gösterir.

İsteğim için doğru İçerik Türü başlığı şuydu:

"Content-Type": "application / x-www-form-urlencoded; karakter kümesi = UTF-8"

Sonuç olarak, form verileriniz İsteğe eklenmiyorsa, muhtemelen üstbilgileriniz olabilir. Başlıklarınızı en aza indirmeye çalışın ve ardından sorununuzun çözülüp çözülmediğini görmek için bunları tek tek eklemeyi deneyin.


3

Bence, JSON nesnesini bir dizeye ayrıştırmaya ihtiyacımız yok, uzak sunucu isteklerine json kabul ederse, sadece çalıştırın:

const request = await fetch ('/echo/json', {
  headers: {
    'Content-type': 'application/json'
  },
  method: 'POST',
  body: { a: 1, b: 2 }
});

Kıvrılma isteği gibi

curl -v -X POST -H 'Content-Type: application/json' -d '@data.json' '/echo/json'

Uzak hizmetin gövde olarak bir json dosyasını kabul etmemesi durumunda, bir dataForm gönderin:

const data =  new FormData ();
data.append ('a', 1);
data.append ('b', 2);

const request = await fetch ('/echo/form', {
  headers: {
    'Content-type': 'application/x-www-form-urlencoded'
  },
  method: 'POST',
  body: data
});

Kıvrılma isteği gibi

curl -v -X POST -H 'Content-type: application/x-www-form-urlencoded' -d '@data.txt' '/echo/form'

2
Bu açık bir şekilde yanlıştır. Json'unuzu dizginlemeniz gerekip gerekmediği sunucu tarafı ile ilgisi yoktur. Bu senin tam olarak ne curlkomut örtük yapıyor! Nesnelerinizi geçmeden önce dizginlemezseniz , isteğinizin gövdesi olarak bodygönderirsiniz "[object Object]". Dev Tools'da yapılan basit bir test bunu size gösterecektir. Açın ve bu sekmeden ayrılmadan bunu deneyin:a = new FormData(); a.append("foo","bar"); fetch("/foo/bar", { method: 'POST', body: {}, headers: { 'Content-type': 'application/json' } })
oligofren

2

JSON yükünüz diziler ve iç içe nesneler içeriyorsa, URLSearchParams jQuery'nin param()yöntemini kullanırdım.

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

Sunucunuz için, bu standart bir HTML gibi görünecek <form>varlık POSTed.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.