如何使用提取API发布表单数据?


118

我的代码:

fetch("api/xxx", {
    body: new FormData(document.getElementById("form")),
    headers: {
        "Content-Type": "application/x-www-form-urlencoded",
        // "Content-Type": "multipart/form-data",
    },
    method: "post",
}

我尝试使用提取API发布表单,其发送的正文如下:

-----------------------------114782935826962
Content-Disposition: form-data; name="email"

test@example.com
-----------------------------114782935826962
Content-Disposition: form-data; name="password"

pw
-----------------------------114782935826962--

(我不知道为什么每次发送时边界数字都会更改...)

我希望它使用“ Content-Type”:“ application / x-www-form-urlencoded”发送数据,我该怎么办?或者,如果我只需要处理它,如何在控制器中解码数据?


向谁回答我的问题,我知道我可以做到:

fetch("api/xxx", {
    body: "email=test@example.com&password=pw",
    headers: {
        "Content-Type": "application/x-www-form-urlencoded",
    },
    method: "post",
}

我想要的是类似jQuery中的$(“#form”)。serialize()(不使用jQuery)或在控制器中解码mulitpart / form-data的方法。谢谢您的回答。


使用有什么问题FormData
guest271314

1
我想将其发布为“ email=test@example.com&password=pw”。可能吗?
Zack

1
“我不知道为什么每次发送时边界数字都会更改……” –边界标识符只是一个随机标识符,它可以是任何东西,并且本身没有任何意义。因此,在那里选择一个随机数并没有错(客户通常这样做)。

Answers:


149

引用(强调我的)MDNFormData

FormData接口提供了一种轻松构造一组代表表单字段及其值的键/值对的XMLHttpRequest.send()方法,然后可以使用该方法轻松发送该键/值对。如果编码类型设置为,则其格式与表单使用的格式相同"multipart/form-data"

因此,使用时FormData您将自己锁定在multipart/form-data。无法将FormData对象作为正文发送并且发送multipart/form-data格式的数据。

如果要发送数据,则application/x-www-form-urlencoded必须将正文指定为URL编码的字符串,或者传递一个URLSearchParams对象。不幸的是,后者不能直接从form元素初始化。如果您不想自己遍历表单元素(可以使用进行迭代HTMLFormElement.elements),则还可以URLSearchParamsFormData对象创建对象:

const data = new URLSearchParams();
for (const pair of new FormData(formElement)) {
    data.append(pair[0], pair[1]);
}

fetch(url, {
    method: 'post',
    body: data,
})
.then(…);

请注意,您无需自己指定Content-Type标题。


正如僧侣时代在注释中所指出的,您还可以直接创建URLSearchParams和传递FormData对象,而不是将值附加到循环中:

const data = new URLSearchParams(new FormData(formElement));

尽管它在浏览器中仍具有一些实验性的支持,所以请确保在使用前对其进行正确的测试。


18
您也可以FormData直接使用对象或直接在构造函数中使用它,而不是使用循环:new URLSearchParams(new FormData(formElement))
和尚时间

@和尚时间在写这个答案的时候,构造函数参数URLSearchParams非常新的,并支持非常有限。

3
抱歉,这不是投诉,只是给以后将要阅读的所有人的便条。
和尚时间

1
@Prasanth您可以自己明确指定内容类型,但必须选择正确的内容类型。不用fetch理会,为您打理就容易了。

1
@chovy URLSearchParams作为大多数对象内置在大多数现代浏览器中,并且可以在Node上运行。

67

客户

不要设置内容类型标题。

// Build formData object.
let formData = new FormData();
formData.append('name', 'John');
formData.append('password', 'John123');

fetch("api/SampleData",
    {
        body: formData,
        method: "post"
    });

服务器

使用该FromForm属性可以指定绑定源是表单数据。

[Route("api/[controller]")]
public class SampleDataController : Controller
{
    [HttpPost]
    public IActionResult Create([FromForm]UserDto dto)
    {
        return Ok();
    }
}

public class UserDto
{
    public string Name { get; set; }
    public string Password { get; set; }
}

4
在这种情况下,这不会发送application/x-www-form-urlencodedOP所要求的数据。

5
对我来说,当我从标题中删除 Content-Type并让浏览器自动执行它时,它就起作用了。谢谢!
克里斯(Chris)

谢谢@regna本应该整天都在努力工作!
ak85

1
如果您未为Fetch设置“ Content-type”,则它将设置为multipart/form-data,这对于表单数据来说应该是这样!然后,您可以multer在expressjs 中使用它轻松解析该数据格式。
kyw

23

您可以将设置bodyURLSearchParams带有作为参数传递的查询字符串的实例

fetch("/path/to/server", {
  method:"POST"
, body:new URLSearchParams("email=test@example.com&password=pw")
})

document.forms[0].onsubmit = async(e) => {
  e.preventDefault();
  const params = new URLSearchParams([...new FormData(e.target).entries()]);
  // fetch("/path/to/server", {method:"POST", body:params})
  const response = await new Response(params).text();
  console.log(response);
}
<form>
  <input name="email" value="test@example.com">
  <input name="password" value="pw">
  <input type="submit">
</form>


2
Reflect.apply(params.set, params, props)这是一种特别难以理解的说法params.set(props[0], props[1])

Reflect.apply(params.set, params, props)从这里的角度来看,@ poke 是可读的。
guest271314

这似乎是这里唯一可行的答案:/谢谢!:)
OZZIE

0

使用FormDatafetch抓取并发送数据


0
function card(fileUri) {
let body = new FormData();
let formData = new FormData();
formData.append('file', fileUri);

fetch("http://X.X.X.X:PORT/upload",
  {
      body: formData,
      method: "post"
  });
 }

7
通常,仅对代码的答案可以通过添加一些有关其工作方式和原因的解释加以改进。在为已有问题的两年老问题添加答案时,重要的是指出您的答案解决了该问题的新方面。
杰森·艾勒
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.