问题
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:
-----------------------------114782935826962
Content-Disposition: form-data; name=\"email\"
test@example.com
-----------------------------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?
To whom answer my question, I know I can do it with:
fetch(\"api/xxx\", {
body: \"email=test@example.com&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.
回答1:
To quote MDN on FormData (emphasis mine):
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 theXMLHttpRequest.send()method. It uses the same format a form would use if the encoding type were set to"multipart/form-data".
So when using FormData you are locking yourself into multipart/form-data. There is no way to send a FormData object as the body and not sending data in the multipart/form-data format.
If you want to send the data as application/x-www-form-urlencoded you will either have to specify the body as an URL-encoded string, or pass a URLSearchParams object. The latter unfortunately cannot be directly initialized from a form element. If you don’t want to iterate through your form elements yourself (which you could do using HTMLFormElement.elements), you could also create a URLSearchParams object from a FormData object:
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-Type header yourself.
As noted by monk-time in the comments, you can also create URLSearchParams and pass the FormData object directly, instead of appending the values in a loop:
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.
回答2:
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 FromForm attribute to specify that binding source is form data.
[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; }
}
回答3:
You can set body to an instance of URLSearchParams with query string passed as argument
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>
来源:https://stackoverflow.com/questions/46640024/how-do-i-post-form-data-with-fetch-api