Bagaimana cara saya memposting data formulir dengan fetch api?

117

Kode saya:

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

Saya mencoba memposting formulir saya menggunakan fetch api, dan tubuh yang dikirimnya seperti:

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

test@example.com
-----------------------------114782935826962
Content-Disposition: form-data; name="password"

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

(Saya tidak tahu mengapa nomor dalam batas berubah setiap kali dikirim ...)

Saya ingin mengirim data dengan "Content-Type": "application / x-www-form-urlencoded", apa yang harus saya lakukan? Atau jika saya hanya harus mengatasinya, bagaimana cara memecahkan kode data di pengontrol saya?


Kepada siapa menjawab pertanyaan saya, saya tahu saya bisa melakukannya dengan:

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

Yang saya inginkan adalah sesuatu seperti $ ("# form"). Serialize () di jQuery (tanpa menggunakan jQuery) atau cara untuk memecahkan kode mulitpart / form-data di controller. Terima kasih atas jawaban Anda.

Zack
sumber
Apa masalah dengan menggunakan FormData?
guest271314
1
Saya ingin mempostingnya sebagai "[email protected]&password=pw". Apa itu mungkin?
Zack
1
“Saya tidak tahu mengapa nomor dalam batas berubah setiap kali dikirim…” - Pengenal batas hanyalah pengenal acak, bisa apa saja dan tidak memiliki arti sendiri. Jadi tidak ada salahnya memilih nomor acak di sana (yang biasanya dilakukan klien).
aduk

Jawaban:

149

Mengutip MDN padaFormData (penekanan saya):

The FormDataantarmuka menyediakan cara untuk dengan mudah membangun satu set pasangan kunci / nilai yang mewakili kolom formulir dan nilai-nilai mereka, yang kemudian dapat dengan mudah dikirim menggunakan XMLHttpRequest.send()metode. Ini menggunakan format yang sama dengan formulir yang akan digunakan jika jenis pengkodean disetel ke"multipart/form-data" .

Jadi saat menggunakan FormDataAnda mengunci diri Anda ke dalam multipart/form-data. Tidak ada cara untuk mengirim FormDataobjek sebagai badan dan tidak mengirimkan data dalam multipart/form-dataformat.

Jika Anda ingin mengirim data karena application/x-www-form-urlencodedAnda harus menentukan isi sebagai string yang dienkode URL, atau meneruskan URLSearchParamsobjek. Sayangnya yang terakhir tidak dapat langsung diinisialisasi dari sebuah formelemen. Jika Anda tidak ingin mengulang sendiri elemen formulir Anda (yang dapat Anda lakukan menggunakan HTMLFormElement.elements), Anda juga dapat membuat URLSearchParamsobjek dari FormDataobjek:

const data = new URLSearchParams();
for (const pair of new FormData(formElement)) {
    data.append(pair[0], pair[1]);
}

fetch(url, {
    method: 'post',
    body: data,
})
.then(…);

Perhatikan bahwa Anda tidak perlu menentukan Content-Typetajuk sendiri.


Seperti yang dicatat oleh monk-time di komentar, Anda juga bisa membuat URLSearchParamsdan meneruskan FormDataobjek secara langsung, daripada menambahkan nilai dalam satu putaran:

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

Ini masih memiliki beberapa dukungan eksperimental di browser, jadi pastikan untuk menguji ini dengan benar sebelum Anda menggunakannya.

menyodok
sumber
18
Anda juga dapat menggunakan objek atau hanya FormDatadi konstruktor secara langsung daripada loop:new URLSearchParams(new FormData(formElement))
monk-time
@ monk-time Pada saat menulis jawaban itu, argumen konstruktor untuk URLSearchParamsmasih sangat baru dan memiliki dukungan yang sangat terbatas.
aduk
3
maaf, itu bukan keluhan, hanya catatan untuk semua orang yang akan membaca ini di masa mendatang.
waktu biksu
1
@Prasanth Anda dapat menentukan sendiri jenis konten secara eksplisit, tetapi Anda harus memilih yang benar . Lebih mudah untuk meninggalkannya dan fetchmengurusnya untuk Anda.
aduk
1
@chovy URLSearchParamsdibangun di sebagian besar browser modern sebagai objek global dan juga berfungsi dari Node.
aduk
67

Klien

Jangan setel header tipe konten.

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

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

Server

Gunakan FromFormatribut untuk menentukan bahwa sumber pengikatan adalah data formulir.

[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; }
}
regnauld
sumber
4
Sementara ini berfungsi, ini tidak mengirim data seperti application/x-www-form-urlencodedyang diminta OP.
aduk
5
Bagi saya, ini berfungsi ketika saya MENGHAPUS Content-Type dari header dan membiarkan browser melakukannya secara otomatis. Terima kasih!
Chris
Terima kasih @regnauld telah mencoba mengerjakan yang satu ini sepanjang hari!
ak85
1
Jika Anda tidak menyetel 'Jenis konten' untuk Pengambilan, ini akan menyetelnya sebagai multipart/form-data, seperti yang seharusnya untuk data formulir! Kemudian Anda dapat menggunakan multerexpressjs untuk mengurai format data tersebut dengan mudah.
kyw
23

Anda dapat menyetel bodyke instance URLSearchParamsdengan string kueri yang diteruskan sebagai argumen

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>

tamu271314
sumber
2
Reflect.apply(params.set, params, props)adalah cara mengucapkan yang sangat tidak terbaca params.set(props[0], props[1]).
aduk
@poke Reflect.apply(params.set, params, props)dapat dibaca dari perspektif di sini.
guest271314
Sepertinya ini satu-satunya jawaban yang berhasil di sini: / terima kasih! :)
OZZIE
0

Gunakan FormDatadan fetchuntuk mengambil dan mengirim data

Kamil Kiełczewski
sumber
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"
  });
 }
soufiane ELAMMARI
sumber
7
Jawaban kode saja umumnya dapat ditingkatkan dengan menambahkan beberapa penjelasan tentang bagaimana dan mengapa mereka bekerja. Saat menambahkan jawaban untuk pertanyaan dua tahun dengan jawaban yang ada, penting untuk menunjukkan aspek baru apa dari pertanyaan yang dijawab oleh jawaban Anda.
Jason Aller