获取:POST JSON 数据

IT技术 javascript json fetch-api
2021-01-29 09:12:28

我正在尝试使用fetch 发布一个 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 的 JSON 回显时,我希望看到我发{a: 1, b: 2}的对象 ( ),但这不会发生 - chrome devtools 甚至没有将 JSON 显示为请求的一部分,这意味着它没有被发送。

6个回答

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

不能使用 ES2017?使用Promise查看@vp_art 的答案

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

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

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

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

我希望看到我发回的对象

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

正确的代码是:

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 有效负载的端点,原始代码是正确的

Content-Type 仍然是 text/html;charset=iso-8859-1 不知道我做错了什么...
2021-03-10 09:12:28
作为记录,这不是发布 JSON 有效负载 - 这是一个表单帖子 ( x-www-form-urlencoded),在名为json. 所以数据是双重编码的。有关干净的 JSON 帖子,请参阅下面@vp_arth 的回答。
2021-03-17 09:12:28
@mindplay.dk 这不是 x-www-form-urlencoded 帖子。Fetch API 总是在 FormData 对象上使用 multipart/form-data 编码。
2021-03-24 09:12:28
@JukkaP 我已经纠正了。我的主要观点是双重编码问题。
2021-03-26 09:12:28
为了安全起见,res.ok如果响应代码是某种错误,最好确认一下。.catch()最后有一个条款也很好我意识到这只是一个示例片段,但在现实世界中使用时请记住这些事情。
2021-03-31 09:12:28

我认为您的问题是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));

这是正确的解决方案,句号- 其他人似乎都对x-www-form-urlencodedvs混淆了application/json,要么不匹配,要么在 url 编码的字符串中双重包装 JSON。
2021-03-22 09:12:28
但这对 jsfiddle 不起作用。所以,我不确定我是否理解你为什么会说“这是正确的解决方案,句号”。不是其他人都在做包装以满足jsfiddle/echo路线的API吗?
2021-04-05 09:12:28
对于那些不熟悉箭头函数的人,您必须返回 res.json()那里,以便在下一次.then()调用中获取数据
2021-04-05 09:12:28

从搜索引擎,我最终在这个主题上使用 fetch 非 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字符串的另一种方法是使用库,而不是像我上面那样输入它。例如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
});
非常感谢,我完全错过了正确的Content-type,我的 PHP 后端没有收到任何东西。'application/x-www-form-urlencoded'正确修复它。
2021-03-16 09:12:28
谢谢你,兄弟!这是最好的回复!我昨天碰壁了几个小时,试图找到一种方法将带有表单数据的“正文”从我的 Web 应用程序发送到我的服务器......一个建议: $ npm install cors --save 这是摆脱“所必需的”模式 : 'no-cors' " 在 Fetch 请求中见github.com/expressjs/cors
2021-03-17 09:12:28
发自内心的感谢。你两次救了我的时间和我的生命:)
2021-03-17 09:12:28
非常感谢您提供查询字符串,我用 JSON.stringify 尝试了很多次,但 ajax 没有返回响应。但是查询字符串可以解决问题。我还发现这是因为 fetch create json for body params 而不是创建字符串。
2021-03-23 09:12:28
谢谢@AlexanderCherednichenko!感谢分享 cors 笔记,这是一个我不知道的有趣笔记。:)
2021-03-30 09:12:28

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

请注意(小心)在线return response.json();响应不是响应 - 这是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

Content-Typeapplication/json,但你的实际body似乎是x-www-form-urlencoded-我不认为这应该工作?如果它确实有效,那么您的服务器必须非常宽容。下面@vp_arth 的答案似乎是正确的。
2021-03-10 09:12:28
@JuanPicado - 在2 年前进行jsfiddle逆向工程之后,它只是一种可行的选择。当然application/json是正确的形式,现在可以使用了。谢谢你的好眼睛:)
2021-03-14 09:12:28
为什么'x-www-form-urlencoded不是application/json有什么不同?
2021-03-25 09:12:28
嗯。奇怪的细节,它以旧方式对我有用fetchstackoverflow.com/questions/41984893/...)而不是application/json. 或许你知道为什么...
2021-03-29 09:12:28

如果您使用纯 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);
});

要使用它,您有变量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');
});
@Mobigital 完全正确,当时我不知道这种细微差别,但现在这是我做的唯一方法
2021-03-16 09:12:28
我认为你的意思是一组不同的论点Object.assign应该是Object.assign({}, api.headers, headers)因为您不想继续将 custom 添加headers到 common 的哈希中api.headers对?
2021-04-01 09:12:28