【问题标题】:Send non-stringified objects with fetch使用 fetch 发送非字符串化对象
【发布时间】:2016-10-05 07:39:33
【问题描述】:

我第一次使用fetch-api 并且在将非字符串化的JSON 对象传递给服务器时遇到了麻烦。 基本上我想实现与此相同的行为:

$.post(url, {"test": "test"}, function(response) {
   console.log(response);
});

fetch 方法正在与对我来说无法访问的 Web API 进行通信,并且需要一个普通的 JSON 对象

通常我只会使用FormData 将数据传递给服务器,但是JSON 将被转换为字符串[Object object]

fetch(url, {
   method: 'POST',
   body: {"test": "test"}
})
   .then(data => data.json())
   .then(json => console.log(json))
   .catch(e => console.error(e));

使用$_POST(这是API 正在使用的)时,正文请求似乎为空,但使用file_get_contents('php://input) 时给出了正确的值。

虽然这与为请求提供的错误 header 有关。所以我尝试添加标题 Ajax 帖子使用:content-type:multipart/form-data;。但是,这也没有任何价值。

我想知道这是否明确有意不使用普通的 JSON 对象作为数据提供,或者我只是遗漏了什么?



这确实有效,但不允许,因为它是 JSON 对象的字符串化版本:

var formData = new FormData();
formData.append('data', JSON.stringify(data));

fetch(url, {
   method: 'POST',
   body: formData
})
   .then(data => data.json())
   .then(json => console.log(json))
   .catch(e => console.error(e));

【问题讨论】:

  • 您是否尝试过简单的body: JSON.stringify(data),因为 JSON 无论如何都只是一个字符串值。这不是真正的object 本身
  • @CodingIntrigue 似乎当我不使用formData 时,它不适用于$_POST。这就是为什么我认为fetch-api 在使用formData 对象时会自动设置标题,但我不知道是哪个。
  • 呃,你的$.postsn-p 也不发送JSON?
  • @Bergi 你的意思是{test: 'test'}应该变成{"test": "test"}?更新:P
  • @nkmol:不,我的意思是$.post 默认发送内容类型为application/x-www-form-urlencoded 的请求。您的对象通过$.param 发送成为“test=test”,而不是通过JSON.stringify 发送成为“{"test":"test"}”。

标签: ecmascript-6 es6-promise form-data fetch-api


【解决方案1】:

首先,我需要发布到 $_POST 使用的 POST 协议。为此,我将application/x-www-form-urlencoded 的标头(这是$_POST 使用的协议,如docs 中所述)添加到获取发布请求:

fetch(url, {
   headers: new Headers({'Content-Type': 'application/x-www-form-urlencoded'}), // Default header which $_POST listens to
   ...

现在$.post 实际发送数据的方式是创建给定对象的序列化字符串(例如:a%5Bone%5D=1)。要将对象转换为序列化字符串,可以使用$.param

fetch(url, {
            headers: new Headers({'Content-Type': 'application/x-www-form-urlencoded'}), // Default header which $_POST listens to
            method: 'POST',
            body: $.param(data)
        })

这将使您能够从 $_POST 检索数据,就像使用简单的 $.post 一样。

【讨论】:

  • 反对者,请让我知道这个答案有什么问题。
【解决方案2】:

假设您的数据位于变量var data = { a: "some data", b: 123 } 中。如果您希望 PHP 中的代码以这种方式访问​​这些字段:

$_POST["a"] == "some data";
$_POST["b"] == 123;

那你需要这样发送formData格式的数据:

var fdata = new FormData();
fdata.append('a', 'some data');
fdata.append('b', '123');

现在您可以发送该数据,PHP 将可以访问分隔字段 ab,但请注意 b 将是一个字符串,而不是一个数字。

如果你想发送一个数组怎么办。假设{ c: ['hello', 'world', '!'] }?您必须遵循 PHP 名称约定并多次添加相同的名称:

var fdata = new FormData();
fdata.append('c[]', 'hello');
fdata.append('c[]', 'world');
fdata.append('c[]', '!');

设置好表单数据实例后,即可作为请求体使用。

【讨论】:

  • 感谢您的宝贵时间。但是,如前所述,手动创建 FormData 不会使它像我想要的那样动态。我找到了答案,将创建一个新答案:)
  • 我不明白你想要达到的活力水平。实际上,查询字符串的解决方案要糟糕得多,因为它有长度限制,并且无法发送大量数据。
  • 虽然,您没有将 URL 编码字符串用作查询字符串,而是用作帖子正文,因此应该没有长度限制。
  • 是的,你是对的。它不是URL encoded string,而是serialized string 表示。改变了那个。所以动态性是我不担心对象本身内部的所有值。想象一下有一个大对象,然后将每个变量手动放入FormData 会很痛苦。截至目前,我在正文中找不到使用 $.param 的任何缺点。
猜你喜欢
  • 2021-12-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-06-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多