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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/46640024/
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:32:08  来源:igfitidea点击:

How do I post form data with fetch api?

javascriptajaxfetch-api

提问by Zack

My code:

我的代码:

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

I tried to post my form using fetch api, and the body it sends is like:

我尝试使用 fetch api 发布我的表单,它发送的正文如下:

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

[email protected]
-----------------------------114782935826962
Content-Disposition: form-data; name="password"

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

(I don't know why the number in boundary is changed every time it sends...)

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

I would like it to send the data with "Content-Type": "application/x-www-form-urlencoded", what should I do? Or if I just have to deal with it, how do I decode the data in my controller?

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



To whom answer my question, I know I can do it with:

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

fetch("api/xxx", {
    body: "[email protected]&password=pw",
    headers: {
        "Content-Type": "application/x-www-form-urlencoded",
    },
    method: "post",
}

What I want is something like $("#form").serialize() in jQuery (w/o using jQuery) or the way to decode mulitpart/form-data in controller. Thanks for your answers though.

我想要的是 jQuery 中的 $("#form").serialize() (不使用 jQuery)或解码控制器中的 mulitpart/form-data 的方法。谢谢你的回答。

回答by poke

To quote MDN on FormData(emphasis mine):

引用MDNFormData(强调我的):

The FormDatainterface provides a way to easily construct a set of key/value pairs representing form fields and their values, which can then be easily sent using the XMLHttpRequest.send()method. It uses the same format a form would use if the encoding type were set to "multipart/form-data".

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

So when using FormDatayou are locking yourself into multipart/form-data. There is no way to send a FormDataobject as the body and notsending data in the multipart/form-dataformat.

因此,在使用时,FormData您将自己锁定在multipart/form-data. 没有办法将FormData对象作为正文发送而不multipart/form-data格式发送数据。

If you want to send the data as application/x-www-form-urlencodedyou will either have to specify the body as an URL-encoded string, or pass a URLSearchParamsobject. The latter unfortunately cannot be directly initialized from a formelement. If you don't want to iterate through your form elements yourself (which you coulddo using HTMLFormElement.elements), you could also create a URLSearchParamsobject from a FormDataobject:

如果要发送数据,则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(…);

Note that you do not need to specify a Content-Typeheader yourself.

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



As noted by monk-timein the comments, you can also create URLSearchParamsand pass the FormDataobject directly, instead of appending the values in a loop:

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

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

This still has some experimental support in browsers though, so make sure to test this properly before you use it.

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

回答by regnauld

Client

客户

Do not set the content-type header.

不要设置内容类型标头。

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

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

Server

服务器

Use the FromFormattribute to specify that binding source is form data.

使用该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; }
}

回答by guest271314

You can set bodyto an instance of URLSearchParamswith query string passed as argument

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

fetch("/path/to/server", {
  method:"POST"
, body:new URLSearchParams("[email protected]&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="[email protected]">
  <input name="password" value="pw">
  <input type="submit">
</form>

回答by Kamil Kie?czewski

Use FormDataand fetchto grab and send data

使用FormDatafetch来抓取和发送数据

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

  console.log('We send post asynchronously (AJAX)');
  e.preventDefault();
}
<form method="POST" action="myapi/send" onsubmit="send(event,this)">
    <input hidden name="crsfToken" value="a1e24s1">
    <input name="email" value="[email protected]">
    <input name="phone" value="123-456-789">
    <input type="submit">    
</form>

Look on chrome console>network before/after 'submit'