2015-04-21 109 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 => { 
    ... 
})