Jak publikować dane formularzy za pomocą api pobierania?


118

Mój kod:

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

Próbowałem opublikować swój formularz za pomocą api pobierania, a treść, którą wysyła, wygląda następująco:

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

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

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

(Nie wiem, dlaczego liczba w granicach jest zmieniana za każdym razem, gdy wysyła ...)

Chciałbym, aby wysyłał dane z "Content-Type": "application / x-www-form-urlencoded", co mam zrobić? A jeśli po prostu muszę sobie z tym poradzić, jak zdekodować dane w kontrolerze?


Komu odpowiadam na moje pytanie, wiem, że mogę to zrobić:

fetch("api/xxx", {
    body: "email=test@example.com&password=pw",
    headers: {
        "Content-Type": "application/x-www-form-urlencoded",
    },
    method: "post",
}

To, czego chcę, to coś takiego jak $ ("# form"). Serialize () w jQuery (bez użycia jQuery) lub sposób na dekodowanie danych mulitpart / form w kontrolerze. Dziękuję jednak za odpowiedzi.


Jaki jest problem z używaniem FormData?
gość271314

1
Chcę wysłać go jako „email=test@example.com&password=pw”. Czy to możliwe?
Zack

1
„Nie wiem, dlaczego liczba w granicach jest zmieniana za każdym razem, gdy wysyła…” - Identyfikator granicy to tylko losowy identyfikator, może być cokolwiek i sam w sobie nie ma żadnego znaczenia. Nie ma więc nic złego w wyborze losowej liczby (co zwykle robią klienci).
poke

Odpowiedzi:


149

Cytując MDNFormData (moje podkreślenie):

FormDataInterfejs zapewnia sposób łatwo skonstruować zestaw par klucz / wartość reprezentujących pola formularzy i ich wartości, które mogą być łatwo przesyłane za pomocą XMLHttpRequest.send()metody. Używa tego samego formatu, jakiego użyłby formularz, gdyby ustawiono typ kodowania"multipart/form-data" .

Więc kiedy używasz FormData, zamykasz się w multipart/form-data. Nie ma możliwości wysłania FormDataobiektu jako treści i nie wysyłania danych w multipart/form-dataformacie.

Jeśli chcesz wysłać dane application/x-www-form-urlencoded, musisz określić treść jako ciąg zakodowany w adresie URL lub przekazać URLSearchParamsobiekt. Tego ostatniego niestety nie można bezpośrednio zainicjować z formelementu. Jeśli nie chcesz iterację swoimi elementów formularzy siebie (co mogłoby zrobić przy użyciu HTMLFormElement.elements), można również utworzyć URLSearchParamsobiekt z FormDataprzedmiotu:

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

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

Pamiętaj, że nie musisz samodzielnie określać Content-Typenagłówka.


Jak zauważył monk-time w komentarzach, możesz również utworzyć URLSearchParamsi przekazać FormDataobiekt bezpośrednio, zamiast dołączać wartości w pętli:

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

To wciąż ma pewne eksperymentalne wsparcie w przeglądarkach, więc upewnij się, że przetestujesz to poprawnie przed użyciem.


18
Możesz także użyć obiektu lub bezpośrednio FormDataw konstruktorze zamiast pętli:new URLSearchParams(new FormData(formElement))
monk-time

@ monk-time W czasie pisania tej odpowiedzi argument konstruktora URLSearchParamsbył bardzo nowy i miał bardzo ograniczone poparcie.
poke

3
przepraszam, to nie była skarga, tylko notatka dla wszystkich, którzy przeczytają to w przyszłości.
czas mnicha

1
@Prasanth Możesz samodzielnie określić typ zawartości, ale musisz wybrać właściwy . Łatwiej jest po prostu to zostawić i fetchzająć się tym za siebie.
poke

1
@chovy URLSearchParamsjest wbudowane w większość nowoczesnych przeglądarek jako obiekt globalny i działa również w środowisku Node.
szturchnij

67

Klient

Nie ustawiaj nagłówka typu zawartości.

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

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

serwer

Użyj FromFormatrybutu, aby określić, że źródłem powiązania są dane formularza.

[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
Chociaż to działa, nie wysyła danych, o application/x-www-form-urlencodedktóre prosi OP.
poke

5
U mnie zadziałało, gdy usunąłem Content-Type z nagłówka i pozwoliłem przeglądarce zrobić to automatycznie. Dzięki!
Chris

Dzięki @regnauld cały dzień próbowałem rozwiązać ten problem!
ak85

1
Jeśli nie ustawisz „Content-type” (Typ zawartości) dla funkcji Fetch, ustawisz go jako multipart/form-data, co powinno być dla danych formularza! Następnie możesz użyć multerw expressjs do łatwej analizy tego formatu danych.
kyw

23

Możesz ustawić bodyna wystąpienie URLSearchParamsz ciągiem zapytania przekazanym jako 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>


2
Reflect.apply(params.set, params, props)jest szczególnie nieczytelnym sposobem powiedzenia params.set(props[0], props[1]).
poke

@poke Reflect.apply(params.set, params, props)można odczytać z perspektywy tutaj.
gość271314

Wydaje się, że jest to jedyna działająca odpowiedź: / dziękuję! :)
OZZIE

0

Użyj FormDatai, fetchaby pobrać i wysłać dane


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
Odpowiedzi zawierające tylko kod można ogólnie poprawić, dodając wyjaśnienie, jak i dlaczego działają. Dodając odpowiedź na pytanie sprzed dwóch lat z istniejącymi odpowiedziami, ważne jest, aby wskazać, jakiego nowego aspektu pytania dotyczy twoja odpowiedź.
Jason Aller
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.