Come inserisco i dati del modulo con fetch api?


117

Il mio codice:

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

Ho provato a pubblicare il mio modulo usando fetch api, e il corpo che invia è come:

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

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

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

(Non so perché il numero in confine viene cambiato ogni volta che invia ...)

Vorrei che inviasse i dati con "Content-Type": "application / x-www-form-urlencoded", cosa devo fare? O se devo solo occuparmene, come decodifico i dati nel mio controller?


A chi risponde alla mia domanda, so di poterlo fare con:

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

Quello che voglio è qualcosa come $ ("# form"). Serialize () in jQuery (senza usare jQuery) o il modo per decodificare multipart / form-data nel controller. Grazie per le tue risposte però.


Qual è il problema con l'utilizzo FormData?
guest271314

1
Voglio pubblicarlo come "email=test@example.com&password=pw". È possibile?
Zack

1
"Non so perché il numero nel confine viene cambiato ogni volta che invia ..." - L'identificatore del confine è solo un identificatore casuale, può essere qualsiasi cosa e non ha alcun significato da solo. Quindi non c'è niente di sbagliato nello scegliere un numero casuale lì (che è ciò che i client di solito fanno).
colpisci il

Risposte:


149

Per citare MDN suFormData (enfasi mia):

L' FormDatainterfaccia fornisce un modo per costruire facilmente una serie di coppie chiave / valore che rappresentano i campi del modulo ei loro valori, che possono quindi essere facilmente inviati utilizzando il XMLHttpRequest.send()metodo. Utilizza lo stesso formato che un modulo utilizzerebbe se il tipo di codifica fosse impostato"multipart/form-data" .

Quindi quando usi FormDatati stai bloccando in multipart/form-data. Non è possibile inviare un FormDataoggetto come corpo e non inviare dati nel multipart/form-dataformato.

Se vuoi inviare i dati come application/x-www-form-urlencodeddovrai specificare il corpo come una stringa con codifica URL o passare un URLSearchParamsoggetto. Quest'ultimo purtroppo non può essere inizializzato direttamente da un formelemento. Se non vuoi iterare tu stesso attraverso i tuoi elementi del modulo (cosa che potresti fare usando HTMLFormElement.elements), puoi anche creare un URLSearchParamsoggetto da un FormDataoggetto:

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

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

Nota che non è necessario specificare Content-Typeun'intestazione da soli.


Come notato da monk-time nei commenti, puoi anche creare URLSearchParamse passare l' FormDataoggetto direttamente, invece di aggiungere i valori in un ciclo:

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

Questo ha ancora un supporto sperimentale nei browser, quindi assicurati di testarlo correttamente prima di usarlo.


18
Puoi anche usare un oggetto o solo FormDatanel costruttore direttamente invece di un ciclo:new URLSearchParams(new FormData(formElement))
monk-time

@ monk-time Al momento della stesura di questa risposta, l'argomento del costruttore URLSearchParamsera molto nuovo e aveva un supporto molto limitato.
colpisci il

3
scusa, non era un reclamo, solo una nota per tutti coloro che leggeranno questo in futuro.
monaco

1
@Prasanth Puoi specificare tu stesso il tipo di contenuto in modo esplicito, ma devi scegliere quello corretto . È più facile lasciarlo fuori e averne fetchcura per te.
colpisci il

1
@chovy URLSearchParamsè integrato nella maggior parte dei browser moderni come oggetto globale e funziona anche da Node.
colpisci il

67

Cliente

Non impostare l'intestazione del tipo di contenuto.

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

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

server

Utilizzare l' FromFormattributo per specificare che l'origine dell'associazione sono i dati del modulo.

[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
Anche se funziona, non invia i dati poiché application/x-www-form-urlencodedè ciò che richiede OP.
colpisci

5
Per me, ha funzionato quando ho RIMOSSO Content-Type dall'intestazione e ho lasciato che il browser lo facesse automaticamente. Grazie!
Chris

Grazie @regna potrebbe aver cercato di risolvere questo problema tutto il giorno!
ak85

1
Se non imposti "Content-type" per Fetch, lo imposterà come multipart/form-data, che è quello che dovrebbe essere per i dati del modulo! Quindi puoi usare multerin expressjs per analizzare facilmente quel formato di dati.
kyw

23

È possibile impostare bodyun'istanza di URLSearchParamscon stringa di query passata come argomento

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)è un modo di dire particolarmente illeggibile params.set(props[0], props[1]).
colpisci il

@poke Reflect.apply(params.set, params, props)è leggibile dalla prospettiva qui.
ospite 271314

Questa sembra essere l'unica risposta funzionante qui: / grazie! :)
OZZIE

0

Utilizzare FormDatae fetchper acquisire e inviare dati


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
Le risposte solo codice possono generalmente essere migliorate aggiungendo qualche spiegazione su come e perché funzionano. Quando si aggiunge una risposta a una domanda vecchia di due anni con le risposte esistenti, è importante sottolineare quale nuovo aspetto della domanda risponde alla propria risposta.
Jason Aller
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.