web-dev-qa-db-ja.com

フェッチAPIでフォームデータを送信するにはどうすればよいですか?

私のコード:

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"

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

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

(境界の数値が送信されるたびに変更される理由はわかりません...)

「Content-Type」:「application/x-www-form-urlencoded」でデータを送信したいのですが、どうすればよいですか?または、単に対処する必要がある場合、コントローラーでデータをデコードするにはどうすればよいですか?


誰が私の質問に答えて、私はそれでできることを知っています:

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

私が欲しいのは、jQueryの$( "#form")。serialize()のようなもの(jQueryを使用しない)またはコントローラーでmulitpart/form-dataをデコードする方法です。あなたの答えをありがとう。

63
Zack

FormDataのMDN (強調鉱山)を引用するには:

FormDataインターフェースは、フォームフィールドとその値を表すキー/値のペアのセットを簡単に構築する方法を提供し、その後XMLHttpRequest.send()を使用して簡単に送信できます方法。 エンコードタイプが"multipart/form-data"に設定されている場合にフォームが使用するのと同じ形式を使用します。

したがって、FormDataを使用すると、multipart/form-dataにロックされます。 FormDataオブジェクトを本文として送信し、notデータをmultipart/form-data形式で送信する方法はありません。

データをapplication/x-www-form-urlencodedとして送信する場合は、本文をURLエンコードされた文字列として指定するか、 URLSearchParams オブジェクトを渡す必要があります。残念ながら、後者はform要素から直接初期化することはできません。自分でフォーム要素を繰り返し処理したくない場合(couldHTMLFormElement.elements を使用して行う)、URLSearchParamsオブジェクトを作成することもできますFormDataオブジェクト:

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));

ただし、これはまだブラウザーでの実験的なサポートがあるため、使用する前にこれを適切にテストしてください。

79
poke

クライアント

Content-typeヘッダーを設定しないでください。

// 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; }
}
36
regnauld

引数としてクエリ文字列を渡して、bodyのインスタンスにURLSearchParamsを設定できます

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>
11
guest271314