Javascript 获取:POST json 数据

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/29775797/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 03:57:34  来源:igfitidea点击:

Fetch: POST json data

javascriptjsonfetch-api

提问by Razor

I'm trying to POST a JSON object using fetch.

我正在尝试使用fetch 发布一个 JSON 对象。

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 echoI'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.

当使用jsfiddle 的 json echo 时,我希望看到我发送{a: 1, b: 2}回( )的对象,但这不会发生 - chrome devtools 甚至没有将 JSON 显示为请求的一部分,这意味着它没有被发送。

回答by Razor

With ES2017 async/awaitsupport, this is how to POSTa JSON payload:

有了 ES2017async/await支持,这是POSTJSON 有效负载的方法:

(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

不能使用 ES2017?使用承诺查看@vp_art 的回答

The question however is asking for an issue caused by a long since fixed chrome bug.
Original answer follows.

然而,问题是问一个由长期修复的 chrome 错误引起的问题
原答案如下。

chrome devtools doesn't even show the JSON as part of the request

chrome devtools 甚至不显示 JSON 作为请求的一部分

This is the real issue here, and it's a bug with chrome devtools, fixed in Chrome 46.

这是这里的真正问题,它是chrome devtools的一个错误,已在 Chrome 46 中修复。

That code works fine - it is POSTing the JSON correctly, it just cannot be seen.

该代码工作正常 - 它正确发布了 JSON,只是无法看到。

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.

这不起作用,因为这不是JSfiddle 的 echo正确格式

The correct codeis:

正确的代码是:

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

对于接受 JSON 有效负载的端点,原始代码是正确的

回答by vp_arth

I think your issue is jsfiddlecan process form-urlencodedrequest only.

我认为您的问题是jsfiddle只能处理form-urlencoded请求。

But correct way to make json request is pass correct jsonas a body:

但是发出 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));

回答by Noitidart

From search engines, I ended up on this topic for non-json posting data with fetch, so thought I would add this.

从搜索引擎,我最终在这个主题上使用 fetch 非 json 发布数据,所以我想我会添加这个。

For non-jsonyou don't have to use form data. You can simply set the Content-Typeheader to application/x-www-form-urlencodedand use a string:

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

An alternative way to build that bodystring, rather then typing it out as I did above, is to use libraries. For instance the stringifyfunction from query-stringor qspackages. So using this it would look like:

构建该body字符串的另一种方法是使用库,而不是像我上面那样输入它。例如stringify来自query-stringqs包的功能。所以使用它看起来像:

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

回答by Krzysztof Safjanowski

After spending some times, reverse engineering jsFiddle, trying to generate payload - there is an effect.

花了一些时间,逆向工程jsFiddle,尝试生成payload——有效果。

Please take eye (care) on line return response.json();where response is not a response - it is promise.

请注意(小心)在线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/&& Firefox > 39 && Chrome > 42

jsFiddle:http: //jsfiddle.net/egxt6cpz/46/&& Firefox > 39 && Chrome > 42

回答by Francisco Presencia

I have created a thin wrapper around fetch() with many improvements if you are using a purely json REST API:

如果您使用纯 json REST API,我已经创建了一个围绕 fetch() 的瘦包装器,并进行了许多改进:

// 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 apiand 4 methods:

要使用它,您有变量api和 4 个方法:

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

And within an asyncfunction:

在一个async函数中:

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

Example with jQuery:

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

回答by Marcus Lind

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.

这与Content-Type. 正如您可能从其他讨论和对这个问题的回答中注意到的那样,有些人能够通过设置Content-Type: 'application/json'. 不幸的是,在我的情况下它不起作用,我的 POST 请求在服务器端仍然是空的。

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.

但是,如果您尝试使用 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'}
})

回答by Green

Had the same issue - no bodywas sent from a client to a server.

有同样的问题 - 没有body从客户端发送到服务器。

Adding Content-Typeheader solved it for me:

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

回答by lama12345

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:

最佳答案不适用于 PHP7,因为它的编码错误,但我可以用其他答案找出正确的编码。此代码还发送身份验证 cookie,您在处理例如 PHP 论坛时可能需要它:

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

回答by user_CC

It might be useful to somebody:

它可能对某人有用:

I was having the issue that formdata was not being sent for my request

我遇到的问题是没有为我的请求发送 formdata

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"
"X-Prototype-Version" : "1.6.1",
"X-Requested-With" : "XMLHttpRequest"

Also as other answers suggest that the Content-Type header needs to be correct.

此外,其他答案表明 Content-Type 标头需要正确。

For my request the correct Content-Type header was:

对于我的请求,正确的 Content-Type 标头是:

"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8"

"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.

所以最重要的是,如果您的表单数据没有附加到请求,那么它可能是您的标题。尝试将您的标题降至最低,然后尝试将它们一一添加以查看您的问题是否已解决。

回答by Daniel García

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:

我认为,我们不需要将 JSON 对象解析为字符串,如果远程服务器接受 json 到他们的请求中,只需运行:

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

Such as the curl request

比如curl请求

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:

如果远程服务器不接受 json 文件作为正文,只需发送一个 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请求

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