web-dev-qa-db-fra.com

Comment POST avec en-tête multipart / form-data et FormData en utilisant fetch

Ceci est un exemple CURL qui fonctionne bien:

curl -X POST \
  <url> \
  -H 'authorization: Bearer <token>' \
  -H 'content-type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW' \
  -F [email protected] \
  -F userId=<userId>

J'essaie de reproduire cette demande en utilisant isomorphic-fetch .

J'ai essayé le code suivant:

const formData = new FormData();
formData.append('file', file);
formData.append('userId', userId);

return fetch(`<url>`, {      
  method: 'POST',
  headers: {
    'Content-Length': file.length
    'Authorization: Bearer <authorization token>',
    'Content-Type': 'multipart/form-data'
  },
  body: formData
})`

J'utilise fs.readFileSync Afin de générer le file passé à FormData.

L'exemple précédent renvoie un code d'état HTTP 401 (Non autorisé) avec un message d'erreur indiquant que le userId incorporé dans le jeton (envoyé via l'en-tête) ne correspond pas au userId transmis de formData.

Donc, je soupçonne que le FormData qui arrive à l'API REST n'est pas correctement formé.

Le problème peut être lié à l'en-tête Content-Length, Mais je n'ai pas trouvé de meilleur moyen de le calculer (si je n'utilise pas l'en-tête Content-Length J'obtiens un 411 En-tête du code d'état HTTP Content-Length Manquant).

Peut-être que cela échoue en raison d'une valeur incorrecte dans l'en-tête Content-Length?

Avez-vous d'autres suggestions sur la raison de l'échec ou sur la meilleure façon de le déboguer?

Si des informations supplémentaires sont nécessaires pour clarifier ce problème, veuillez simplement demander.

[~ # ~] mise à jour [~ # ~]

J'ai essayé le module form-data afin d'obtenir la bonne valeur Content-Length En utilisant la méthode formData.getLengthSync()

Cependant, le problème reste le même (erreur 401 Réponse du code d'état HTTP).

6
rfc1484

Si vous ouvrez votre inspecteur de réseau, exécutez cet extrait de code et soumettez le formulaire, vous devriez voir que le Content-Length est défini correctement:

const foo = document.getElementById('foo')
foo.addEventListener('submit', (e) => {
  e.preventDefault()
  const formData = new FormData(foo)
  formData.append('userId', 123)
  fetch('//example.com', {
    method: 'POST',
    body: formData
  })
})
<form id="foo">
  <input id="file" type="file" name="file"/><br><br>
  <button type="submit">Submit</button>
</form>

4
idbehold

Je me suis cogné la tête contre un mur similaire, en utilisant spécifiquement isomorphic-fetch Sur le nœud pour POST un formulaire en plusieurs parties. La clé pour moi était de trouver .getHeaders(). Notez que description NPM pour form-data suggère que cela "fonctionnera" sans cela, mais cela ne semble pas, du moins pas dans le nœud (je pense que les navigateurs injectent des éléments d'en-tête?) .

// image is a Buffer containing a PNG image
// auth is the authorization token

const form_data  = new FormData();
form_data.append("image", png, {
    filename: `image.png`,
    contentType: 'application/octet-stream',
    mimeType: 'application/octet-stream'
});

const headers = Object.assign({
    'Accept': 'application/json',
    'Authorization': auth,
}, form_data.getHeaders());

try {
    const image_res = await fetch(url, {
        method: 'POST',
        headers: headers,
        body: form_data
    });

    if (!image_res.ok) {
        const out = await image_res.json();
        console.dir(out);
        return;
    }
}
catch (e) {
    console.error(`Chart image generation exception: ${e}`);
}
2
Iain Bryson