可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I\'m trying to POST a JSON object using fetch.
From what I can understand, I need to attach a stringified object to the body of the request, e.g.:
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) })
When using jsfiddle\'s json echo I\'d expect to see the object I\'ve sent ({a: 1, b: 2}
) back, but this does not happen - chrome devtools doesn\'t even show the JSON as part of the request, which means that it\'s not being sent.
回答1:
With ES2017 async/await
support, this is how to POST
a JSON payload:
(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);
})();
Can\'t use ES2017? See @vp_art\'s answer using promises
The question however is asking for an issue caused by a long since fixed chrome bug.
Original answer follows.
chrome devtools doesn\'t even show the JSON as part of the request
This is the real issue here, and it\'s a bug with chrome devtools, fixed in Chrome 46.
That code works fine - it is POSTing the JSON correctly, it just cannot be seen.
I\'d expect to see the object I\'ve sent back
that\'s not working because that is not the correct format for JSfiddle\'s echo.
The correct code is:
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 ) ) })
For endpoints accepting JSON payloads, the original code is correct
回答2:
I think your issue is jsfiddle
can process form-urlencoded
request only.
But correct way to make json request is pass correct json
as a body:
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));
回答3:
From search engines, I ended up on this topic for non-json posting data with fetch, so thought I would add this.
For non-json you don\'t have to use form data. You can simply set the Content-Type
header to application/x-www-form-urlencoded
and use a 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: \'foo=bar&blah=1\'
});
An alternative way to build that body
string, rather then typing it out as I did above, is to use libraries. For instance the stringify
function from query-string
or qs
packages. So using this it would look like:
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}
});
回答4:
After spending some times, reverse engineering jsFiddle, trying to generate payload - there is an effect.
Please take eye (care) on line return response.json();
where response is not a response - it is promise.
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
回答5:
I have created a thin wrapper around fetch() with many improvements if you are using a purely 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);
});
To use it you have the variable api
and 4 methods:
api.get(\'/todo\').then(all => { /* ... */ });
And within an async
function:
const all = await api.get(\'/todo\');
// ...
Example with 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\');
});
回答6:
Had the same issue - no body
was sent from a client to a server.
Adding Content-Type
header solved it for me:
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:
This is related to Content-Type
. As you might have noticed from other discussions and answers to this question some people were able to solve it by setting Content-Type: \'application/json\'
. Unfortunately in my case it didn\'t work, my POST request was still empty on the server side.
However, if you try with jQuery\'s $.post()
and it\'s working, the reason is probably because of jQuery using Content-Type: \'x-www-form-urlencoded\'
instead of 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\'}
})
回答8:
It might be useful to somebody:
I was having the issue that formdata was not being sent for my request
In my case it was a combination of following headers that were also causing the issue and the wrong Content-Type.
So I was sending these two headers with the request and it wasn\'t sending the formdata when I removed the headers that worked.
\"X-Prototype-Version\" : \"1.6.1\",
\"X-Requested-With\" : \"XMLHttpRequest\"
Also as other answers suggest that the Content-Type header needs to be correct.
For my request the correct Content-Type header was:
\"Content-Type\": \"application/x-www-form-urlencoded; charset=UTF-8\"
So bottom line if your formdata is not being attached to the Request then it could potentially be your headers. Try bringing your headers to a minimum and then try adding them one by one to see if your problem is rsolved.
回答9:
The top answer doesn\'t work for PHP7, because it has wrong encoding, but I could figure the right encoding out with the other answers. This code also sends authentication cookies, which you probably want when dealing with e.g. 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);
});
}
回答10:
If your JSON payload contains arrays and nested objects, I would use URLSearchParams
and jQuery\'s param()
method.
fetch(\'/somewhere\', {
method: \'POST\',
body: new URLSearchParams($.param(payload))
})
To your server, this will look like a standard HTML <form>
being POST
ed.
回答11:
I think that, we don\'t need parse the JSON object into a string, if the remote server accepts json into they request, just run:
const request = await fetch (\'/echo/json\', {
headers: {
\'Content-type\': \'application/json\'
},
method: \'POST\',
body: { a: 1, b: 2 }
});
Such as the curl request
curl -v -X POST -H \'Content-Type: application/json\' -d \'@data.json\' \'/echo/json\'
In case to the remote serve not accept a json file as the body, just send a dataForm:
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
});
Such as the curl request
curl -v -X POST -H \'Content-type: application/x-www-form-urlencoded\' -d \'@data.txt\' \'/echo/form\'