如何使用 fetch api 发布表单数据?

IT技术 javascript ajax fetch-api
2021-02-06 08:50:11

我的代码:

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

我尝试使用 fetch 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 的方法。谢谢你的回答。

6个回答

引用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自己指定标题。


正如monk-time在评论中所指出的,您还可以直接创建URLSearchParams和传递FormData对象,而不是在循环中附加值:

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

不过,这在浏览器中仍然有一些实验性支持,因此请确保在使用之前对其进行正确测试。

@monk-time 在撰写该答案时,构造函数参数 toURLSearchParams非常新的并且支持非常有限。
2021-03-22 08:50:11
@Prasanth 您可以自己明确指定内容类型,但您必须选择正确的类型放下它并fetch为您照顾它会更容易
2021-03-26 08:50:11
抱歉,这不是抱怨,只是给将来会阅读本文的每个人的注释。
2021-03-27 08:50:11
如果您需要发布 FormData,则无需使用URLSearchParams fetch(url, { method: 'post', body: new FormData(form_element), })
2021-03-31 08:50:11
您还可以FormData直接在构造函数中使用对象或仅在构造函数中使用,而不是使用循环:new URLSearchParams(new FormData(formElement))
2021-04-06 08:50:11

客户

不要设置内容类型标头。

// 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; }
}
对我来说,当我从标题中删除 Content-Type并让浏览器自动执行时,它起作用了。谢谢!
2021-03-22 08:50:11
如果您没有为 Fetch 设置 'Content-type',它会将其设置为multipart/form-data,这就是表单数据应该设置的!然后你可以multer在 expressjs中使用它来轻松解析该数据格式。
2021-03-25 08:50:11
虽然这有效,但这不会发送application/x-www-form-urlencodedOP 要求的数据。
2021-04-12 08:50:11

您可以设置bodyURLSearchParamswith 查询字符串作为参数传递的实例

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>

这似乎是这里唯一有效的答案:/谢谢!:)
2021-03-18 08:50:11
如果我通过body:new URLSearchParams("img="+my5MBimage)发送5MB 图像文件怎么办?
2021-03-28 08:50:11
@PYK 在这种情况下,您不能使用 application/x-www-form-urlencoded 而是 multipart/form-data: application/x-www-form-urlencoded 或 multipart/form-data?
2021-04-04 08:50:11
@pokeReflect.apply(params.set, params, props)从这里的角度是可读的。
2021-04-09 08:50:11
Reflect.apply(params.set, params, props)是一种特别难以理解的说法params.set(props[0], props[1])
2021-04-12 08:50:11

使用FormDatafetch来抓取和发送数据

fetch(form.action, {method:'post', body: new FormData(form)});

@MarcoMannes 如果您mehtod:'post'fetch上面代码片段中的参数中删除,您将收到Request with GET/HEAD method cannot have body.异常。如果您method="POST"从上述代码段中的 html 中删除method:'post'(在 fetch params 中)将生效 - 浏览器将发送 POST - 我通过修改此代码段并使用 chrome>network 选项卡来检查这一点(因此实际上我们可以从 html 中删除它...但我会离开它)
2021-03-21 08:50:11
非常感谢,这就是我一直在寻找的东西,现在纯 JavaScript 变得如此简单,真是太神奇了。只要看看那个美丽1个衬垫 fetch代码post<form>数据,我仍然惊讶我是怎么发现这一点。再见 jQuery。
2021-04-02 08:50:11
该选项method: 'post'无效,因为浏览器将使用form传递给FormData. 即使在form浏览器中未定义方法属性时,也会回退到默认GET方法。
2021-04-02 08:50:11
这里根本不重要,但隐藏输入的名称中有一个错字。对于那些想知道为什么会有这种输入的人来说,它csrf代表跨站点请求伪造。
2021-04-06 08:50:11
form.action 是端点 url 吗?
2021-04-07 08:50:11

使用 fetch api,结果证明您不必包含标题“Content-type”:“multipart/form-data”。

所以以下工作:

let formData = new FormData()
formData.append("nameField", fileToSend)

fetch(yourUrlToPost, {
   method: "POST",
   body: formData
})

请注意,使用 axios 我必须使用内容类型。

我正在将一个文件和一些数据从 React 发送到 Flask,直到我删除了 Content-type,它才起作用。谢谢 :)
2021-03-27 08:50:11