2015-04-21 106 views
209

我想使用fetch發佈一個JSON對象。取:POST JSON數據

從我能理解,我需要一個字符串化對象附加到請求的主體,如:

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's json echo我希望看到我送的對象({a: 1, b: 2} ),但這不會發生 - chrome devtools甚至不會將JSON顯示爲請求的一部分,這意味着它不會被髮送。

+0

您使用的是什麼瀏覽器? –

+0

@KrzysztofSafjanowski chrome 42,這意味着[完全獲取支持](http://caniuse.com/#search=fetch) – Razor

+0

檢查此小提琴https://jsfiddle.net/abbpbah4/2/什麼數據你'重新期待?因爲https://fiddle.jshell.net/echo/json的請求顯示空對象。 '{}' –

回答

137

鉻devtools甚至不顯示的JSON作爲請求

的一部分。這是真正的問題在這裏,它是一個bug with chrome devtools,固定在Chrome 46.

該代碼工作正常 - 它正確發佈JSON,它只是無法看到。

我希望看到的是不工作我送回

的對象,因爲這不是correct format for JSfiddle's echo

correct code是:

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有效載荷,原來的代碼是正確的

+7

爲了記錄,這不是發佈JSON有效負載 - 這是一個表單文章('x-www-form-urlencoded'),其中的JSON數據位於名爲'json'的字段中。所以數據是雙重編碼的。對於乾淨的JSON文章,請參閱下面的@vp_arth回答。 –

24

經過一段時間後,反向工程jsFiddle,試圖產生有效載荷 - 有一個效果。

請注意行return response.json();行(護理),其中響應不是一個響應 - 這是承諾。

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/ & &火狐> 39 & &鉻> 42個

+0

爲什麼'x-www-form-urlencoded'而不是'application/json'?有什麼不同? –

+0

@JuanPicado - 在** jsfiddle ** 2年前的逆向工程中,只有一個選擇,它可以工作。當然'application/json'是正確的形式,它現在可以工作。感謝您的好評:) –

+0

yw。好奇的細節,它在''fetch'以舊的方式爲我工作(http://stackoverflow.com/questions/41984893/fetch-post-fails-on-post-json-body-with-sails-js?noredirect = 1#comment71171442_41984893)而不是'application/json'。也許你知道爲什麼...... –

24

來自搜索引擎,我結束了對這個話題有取非JSON帳數據,所以想到我會補充這一點。

對於非json您不必使用表單數據。你可以簡單的Content-Type頭設置爲application/x-www-form-urlencoded和使用字符串:

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

的另一種方式來構建body字符串,而不是鍵入它作爲我上面那樣使用庫。例如query-stringqs封裝的stringify功能。因此,使用這一點,看起來像:

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

非常感謝你的查詢字符串,我用JSON.stringify嘗試了很多次,但是ajax沒有返回響應。但查詢字符串做了訣竅。我還發現,這是因爲fetch爲body params創建json而不是創建一個字符串。 – Danish

+1

謝謝你的男人!這是最好的回覆!我昨天碰壁了幾個小時試圖找到一種方法來發送表單數據從我的web應用程序到我的服務器'身體'...一個建議:$ npm install cors --save這是需要擺脫「模式:'no-cors'「在請求請參閱https://github.com/expressjs/cors –

+0

謝謝@AlexanderCherednichenko!並感謝您分享這些注意到這是一個我不知道的有趣的。 :) – Noitidart

94

我覺得你的問題是jsfiddle只能處理form-urlencoded請求。

但是,爲了使JSON請求正確的方法是通過正確的json爲一體:

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。在asp.net mvc中正確的解決方案。 –

+2

這是正確的解決方案,_period_ - 其他人似乎混淆了'x-www-form-urlencoded'與'application/json',要麼不匹配,要麼在url編碼的字符串中重複包裝JSON。 –

10

我有,如果你使用的是創建一個簡單包裝的取()有許多改進純粹的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); 
}); 

要使用它,你有變量api和4的方法:

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

而一個async函數內:

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

實施例與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

我想你是指'Object.assign'的一組不同的參數?應該是'Object.assign({},api.headers,headers)',因爲你不想在常見的'api.headers'的哈希中添加自定義的'headers'。對? – Mobigital

+0

@Mobigital完全正確,當時我不知道那個細微差別,但現在它是我做這件事的唯一方式 –

3

這與Content-Type。正如你可能從其他討論和這個問題的答案中已經注意到的,有些人可以通過設置Content-Type: 'application/json'來解決這個問題。不幸的是,在我的情況下,它不起作用,我的POST請求在服務器端仍然是空的。

但是,如果你嘗試使用jQuery的$.post(),它的工作原理可能是因爲jQuery使用Content-Type: 'x-www-form-urlencoded'而不是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

我的後端開發人員用PHP構建了API,期望數據是查詢字符串而不是json對象。這解決了服務器端的空白響應。 – eballeste

6

有同樣的問題 - 沒有body是從客戶端發送到服務器。

添加Content-Type頭解決了這個問題對我來說:

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