web-dev-qa-db-fra.com

JavaScript: fichier de téléchargement

Disons que j'ai cet élément sur la page:

<input id="image-file" type="file" />

Cela créera un bouton permettant aux utilisateurs de la page Web de sélectionner un fichier via une boîte de dialogue du système d'exploitation "Fichier ouvert ..." dans le navigateur.

Supposons que l'utilisateur clique sur ledit bouton, sélectionne un fichier dans la boîte de dialogue, puis clique sur le bouton "OK" pour fermer la boîte de dialogue.

Le nom de fichier sélectionné est maintenant stocké dans:

document.getElementById("image-file").value

Supposons maintenant que le serveur gère des POST en plusieurs parties à l'URL "/ upload/image".

Comment puis-je envoyer le fichier à "/ upload/image"?

De plus, comment puis-je écouter pour être informé que le téléchargement du fichier est terminé?

152
YummyBánhMì

Sauf si vous essayez de télécharger le fichier en utilisant ajax, il vous suffit de soumettre le formulaire à /upload/image.

<form enctype="multipart/form-data" action="/upload/image" method="post">
    <input id="image-file" type="file" />
</form>

Si vous souhaitez télécharger l'image en arrière-plan (par exemple, sans envoyer l'intégralité du formulaire), vous pouvez utiliser ajax:

90
Matt Ball

Pure JS

Vous pouvez utiliser fetch éventuellement avec wait-try-catch

let photo = document.getElementById("image-file").files[0];
let formData = new FormData();

formData.append("photo", photo);
fetch('/upload/image', {method: "POST", body: formData});
async function SavePhoto(inp) 
{
    let user = { name:'john', age:34 };
    let formData = new FormData();
    let photo = inp.files[0];      
         
    formData.append("photo", photo);
    formData.append("user", JSON.stringify(user));  
    
    try {
       let r = await fetch('/upload/image', {method: "POST", body: formData}); 
       console.log('HTTP response code:',r.status); 
    } catch(e) {
       console.log('Huston we have problem...:', e);
    }
    
}
<input id="image-file" type="file" onchange="SavePhoto(this)" >
<br><br>
Before selecting the file open chrome console > network tab to see the request details.
<br><br>
<small>Because in this example we send request to https://stacksnippets.net/upload/image the response code will be 404 ofcourse...</small>

<br><br>
(in stack overflow snippets there is problem with error handling, however in <a href="https://jsfiddle.net/Lamik/b8ed5x3y/5/">jsfiddle version</a> for 404 errors 4xx/5xx are <a href="https://stackoverflow.com/a/33355142/860099">not throwing</a> at all but we can read response status which contains code)

Old School Approach - xhr

let photo = document.getElementById("image-file").files[0];  // file from input
let req = new XMLHttpRequest();
let formData = new FormData();

formData.append("photo", photo);                                
req.open("POST", '/upload/image');
req.send(formData);
function SavePhoto(e) 
{
    let user = { name:'john', age:34 };
    let xhr = new XMLHttpRequest();
    let formData = new FormData();
    let photo = e.files[0];      
    
    formData.append("user", JSON.stringify(user));   
    formData.append("photo", photo);
    
    xhr.onreadystatechange = state => { console.log(xhr.status); } // err handling
    xhr.open("POST", '/upload/image');    
    xhr.send(formData);
}
<input id="image-file" type="file" onchange="SavePhoto(this)" >
<br><br>
Choose file and open chrome console > network tab to see the request details.
<br><br>
<small>Because in this example we send request to https://stacksnippets.net/upload/image the response code will be 404 ofcourse...</small>

<br><br>
(the stack overflow snippets, has some problem with error handling - the xhr.status is zero (instead of 404) which is similar to situation when we run script from file on <a href="https://stackoverflow.com/a/10173639/860099">local disc</a> - so I provide also js fiddle version which shows proper http error code <a href="https://jsfiddle.net/Lamik/k6jtq3uh/2/">here</a>)

RÉSUMÉ

  • Sur le côté serveur, vous pouvez lire le nom de fichier d'origine (et d'autres informations), automatiquement inclus dans la requête.
  • Vous n'avez PAS besoin de définir l'en-tête de demande Content-Type sur multipart/form-data - il sera automatiquement défini par le navigateur.
  • Au lieu de /upload/image, vous pouvez utiliser une adresse complète comme http://.../upload/image.
  • Vous pouvez inclure des données supplémentaires (json) pour demander, par exemple, let user = {name:'john', age:34} de cette manière: formData.append("user", JSON.stringify(user));
  • Cette solution devrait fonctionner sur tous les principaux navigateurs.
38
Kamil Kiełczewski

Si vous cherchez en fait une méthode purement javascript pour télécharger une image, le didacticiel suivant de 2009 vous expliquera exactement comment procéder:

http://igstan.ro/posts/2009-01-11-ajax-file-upload-with-pure-javascript.html

Je me suis heurté à cela lorsque je voulais ajouter une authentification de base à une soumission de formulaire, sans activer les cookies. Par exemple. lorsque vous avez des champs nom d'utilisateur/mot de passe avec vos champs nom de fichier, fichier, etc.

J'espère que cela t'aides!

24
dwh

En tant que créateur, je suis partial;) mais vous pouvez aussi envisager d’utiliser quelque chose comme https://uppy.io . Il effectue le téléchargement de fichiers sans quitter la page et offre quelques bonus, tels que le glisser-déposer, la reprise des téléchargements en cas de blocage du réseau ou de réseaux volumineux, et l'importation à partir de, par exemple. Instagram. Il est également open source et ne repose pas sur jQuery ou quoi que ce soit du genre.

6
kvz