フェッチAPIを使用してフォームデータを投稿するにはどうすればよいですか?


116

私のコード:

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をデコードする方法です。回答ありがとうございます。


使用に関する問題は何FormDataですか?
guest271314

1
「email=test@example.com&password=pw」として投稿したい。出来ますか?
ザック

1
「境界内の数値が送信されるたびに変更される理由がわかりません...」 –境界識別子は単なるランダムな識別子であり、何でも可能であり、それ自体には意味がありません。したがって、そこで乱数を選択することに問題はありません(クライアントが通常行うことです)。
突く

回答:


148

MDNFormDataを引用(私の強調):

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

したがって、使用FormDataするときは、自分をに閉じ込めていますmultipart/form-dataFormData本体としてオブジェクトを送信する方法はなく、形式でデータを送信することはできませんmultipart/form-data

データを送信するapplication/x-www-form-urlencoded場合は、本文をURLエンコードされた文字列として指定するか、URLSearchParamsオブジェクトを渡す必要があります。後者は残念ながらform要素から直接初期化することはできません。自分でフォーム要素を反復処理したくない場合(を使用して実行できますHTMLFormElement.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で指摘されているように、ループで値を追加する代わりにURLSearchParamsFormDataオブジェクトを直接作成して渡すこともできます。

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

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


18
また、オブジェクトまたは単に使用することができますFormData:コンストラクタではなく直接のループnew URLSearchParams(new FormData(formElement))
僧侶タイム

@ monk-timeその回答を書いている時点では、コンストラクタの引数URLSearchParams非常に新しく、サポートは非​​常に限られていました。
突く

3
申し訳ありませんが、これは不満ではなく、将来これを読むすべての人へのメモです。
モンク時間

1
@Prasanthコンテンツタイプを自分で明示的に指定できますが、正しいものを選択する必要があります。そのままにしておいたほうが簡単fetchです。
突く

1
@chovy URLSearchParamsは、ほとんどの最新のブラウザーにグローバルオブジェクトとして組み込まれており、Nodeからも機能します。
突く

67

クライアント

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

4
これは機能しますapplication/x-www-form-urlencodedが、OPが要求するデータは送信されません。
突く

5
私にとっては、ヘッダーから削除 Content-Typeし、ブラウザーに自動的に実行させると機能しました。ありがとう!
Chrisが

ありがとう、@ regnauldはこれを一日中解決しようとしてきた!
ak85

1
Fetchに 'Content-type'を設定しない場合は、それをに設定しますmultipart/form-data。これは、フォームデータの場合と同じです。次にmulter、expressjsを使用して、そのデータ形式を簡単に解析できます。
kyw

23

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

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])
突く

@poke Reflect.apply(params.set, params, props)は、ここでは見やすいです。
-guest271314

これがここでの唯一の有効な答えのようです:/ありがとうございます!:)
OZZIE

0

FormDataおよびfetchを使用してデータを取得して送信する


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
コードのみの回答は、一般に、それらがどのようにそしてなぜ機能するかについての説明を追加することによって改善できます。既存の回答を使用して2年前の質問に回答を追加するときは、回答の対象となる質問の新しい側面を指摘することが重要です。
Jason Aller
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.