182 votes

Comment afficher les données du formulaire avec l'api fetch ?

Mon code :

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

J'ai essayé de poster mon formulaire en utilisant l'api fetch, et le corps qu'il envoie est comme :

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

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

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

(Je ne sais pas pourquoi le nombre en limite est changé à chaque envoi...)

Je voudrais qu'il envoie les données avec "Content-Type" : "application/x-www-form-urlencoded", que dois-je faire ? Ou si je dois faire avec, comment décoder les données dans mon contrôleur ?


Pour qui répond à ma question, je sais que je peux le faire avec :

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

Ce que je veux, c'est quelque chose comme $("#form").serialize() en jQuery (sans utiliser jQuery) ou le moyen de décoder les données multipart/formulaires dans le contrôleur. Merci pour vos réponses.

0 votes

Quel est le problème avec l'utilisation de FormData ?

1 votes

Je veux l'afficher comme "email=test@example.com&password=pw". Est-ce possible ?

1 votes

"Je ne sais pas pourquoi le numéro dans les limites est changé à chaque fois qu'il envoie " - L'identifiant de frontière est juste un identifiant aléatoire, il peut être n'importe quoi et n'a aucune signification en soi. Il n'y a donc rien de mal à choisir un nombre aléatoire à cet endroit (ce que font généralement les clients).

209voto

poke Points 64398

Je cite MDN sur FormData (c'est moi qui souligne) :

Le site FormData permet de construire facilement un ensemble de paires clé/valeur représentant les champs de formulaire et leurs valeurs, qui peuvent ensuite être facilement envoyées à l'aide de l'interface XMLHttpRequest.send() méthode. Il utilise le même format que celui qu'un formulaire utiliserait si le type d'encodage était fixé à "multipart/form-data" .

Ainsi, lorsque vous utilisez FormData vous vous enfermez dans multipart/form-data . Il n'y a aucun moyen d'envoyer un FormData comme corps et pas l'envoi de données dans le multipart/form-data format.

Si vous voulez envoyer les données en tant que application/x-www-form-urlencoded vous devrez soit spécifier le corps sous la forme d'une chaîne codée en URL, soit passer un fichier URLSearchParams objet. Ce dernier ne peut malheureusement pas être initialisé directement à partir d'un objet de type form élément. Si vous ne voulez pas itérer vous-même à travers les éléments de votre formulaire (ce que vous pouvez faire), vous pouvez utiliser la fonction d'itération. pourrait utiliser HTMLFormElement.elements ), vous pouvez également créer un URLSearchParams à partir d'un FormData objet :

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

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

Notez que vous n'avez pas besoin de spécifier un Content-Type l'entête vous-même.


Comme l'a noté l'heure du moine dans les commentaires, vous pouvez également créer URLSearchParams et passer le FormData directement, au lieu d'ajouter les valeurs dans une boucle :

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

Cependant, la prise en charge par les navigateurs est encore expérimentale. Veillez donc à la tester correctement avant de l'utiliser.

32 votes

Vous pouvez également utiliser un objet ou simplement FormData dans le constructeur directement au lieu d'une boucle : new URLSearchParams(new FormData(formElement))

1 votes

@monk-time Au moment de l'écriture de cette réponse, l'argument du constructeur à URLSearchParams était très nouveau et bénéficiait d'un soutien très limité.

4 votes

Désolé, ce n'était pas une plainte, juste une note pour tous ceux qui liront ceci à l'avenir.

105voto

regnauld Points 1142

Client

Ne pas définir l'en-tête content-type.

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

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

Serveur

Utilisez le FromForm pour préciser que la source de liaison est constituée de données de formulaire.

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

5 votes

Bien que cela fonctionne, cela ne permet pas d'envoyer les données en tant que application/x-www-form-urlencoded ce qui est ce que le PO demande.

6 votes

Pour moi, ça a marché quand j'ai REMOVED Content-Type de l'en-tête et laisser le navigateur le faire automatiquement. Merci !

1 votes

Si vous ne définissez pas 'Content-type' pour Fetch, il le définira comme étant multipart/form-data C'est ce qu'il devrait être pour les données de formulaire ! Vous pouvez alors utiliser multer dans expressjs pour analyser facilement ce format de données.

33voto

guest271314 Points 2718

Vous pouvez définir body à une instance de URLSearchParams avec la chaîne de requête passée comme 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 votes

Reflect.apply(params.set, params, props) est une façon particulièrement illisible de dire params.set(props[0], props[1]) .

0 votes

@poke Reflect.apply(params.set, params, props) est lisible en perspective ici.

0 votes

Cela semble être la seule réponse qui fonctionne ici :/ merci ! :)

11voto

Kamil Kiełczewski Points 6496

Utilisez FormData et fetch pour saisir et envoyer des données

fetch(form.action, {method:'post', body: new FormData(form)});

function send(e,form) {
  fetch(form.action, {method:'post', body: new FormData(form)});

  console.log('We send post asynchronously (AJAX)');
  e.preventDefault();
}

<form method="POST" action="myapi/send" onsubmit="send(event,this)">
    <input hidden name="csrfToken" value="a1e24s1">
    <input name="email" value="a@b.com">
    <input name="phone" value="123-456-789">
    <input type="submit">    
</form>

Look on chrome console>network before/after 'submit'

2 votes

Merci beaucoup, c'est ce que je cherchais et c'est incroyable à quel point le JavaScript pur peut être facile de nos jours. Il suffit de regarder cette belle 1 doublure fetch le code qui post le site <form> données, je suis toujours étonné d'avoir trouvé ça. Bye bye jQuery.

0 votes

Ce n'est pas du tout important ici, mais il y a une faute de frappe dans le nom de l'entrée cachée. Pour tous ceux qui se demandent pourquoi cette entrée est là, csrf est l'abréviation de Cross-site Request Forgery.

5voto

nicolass Points 71

Avec fetch api, il s'est avéré que vous n'avez PAS besoin d'inclure les en-têtes "Content-type" : "multipart/form-data".

Donc, ce qui suit fonctionne :

let formData = new FormData()
formData.append("nameField", fileToSend)

fetch(yourUrlToPost, {
   method: "POST",
   body: formData
})

Notez qu'avec axios, j'ai dû utiliser le content-type.

0 votes

J'envoie un fichier et des données de React à Flask et cela ne fonctionnait pas jusqu'à ce que je retire Content-type. Merci :)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X