2016-03-17 17 views
57

Sto ancora cercando di avvolgere la mia mente intorno ad esso.Come caricare un file con l'API di recupero JS?

posso avere l'utente selezionare il file (o anche più) con l'ingresso di file:

<form> 
    <div> 
    <label>Select file to upload</label> 
    <input type="file"> 
    </div> 
    <button type="submit">Convert</button> 
</form> 

e posso catturare l'evento submit utilizzando <fill in your event handler here>. Ma una volta fatto, come posso inviare il file usando fetch?

fetch('/files', { 
    method: 'post', 
    // what goes here? What is the "body" for this? content-type header? 
}).then(/* whatever */); 

risposta

36

Questo è un semplice esempio e commentato, la funzione upload è ciò che stai per lookig:

// Select your input type file and store it in a variable 
const input = document.getElementById('fileinput'); 

// This will upload the file after having read it 
const upload = (e) => { 
    fetch('www.example.net', { // Your POST endpoint 
    method: 'POST', 
    headers: { 
     "Content-Type": "You will perhaps need to define a content-type here" 
    }, 
    body: e.currentTarget.result // This is the content of your file 
    }).then(
    response => response.json() // if the response is a JSON object 
).then(
    success => console.log(success); // Handle the success response object 
).catch(
    error => console.log(error); // Handle the error response object 
); 
}; 

// Event handler executed when a file is selected 
const onSelectFile = (files) => { 
    // Files is a list because you can select several files 
    // We just upload the first selected file 
    const file = input.files[0]; 
    const reader = new FileReader(); 

    // We read the file and call the upload function with the result 
    reader.onload = upload; 
    reader.readAsText(file); 
}; 

// Add a listener on your input 
// It will be triggered when a file will be selected 
input.addEventListener('change', onSelectFile , false); 
+1

Quindi ero vicino, ma non proprio lì. Cosa fai con i file più grandi? Sta caricando tutto nella memoria del browser o lo sta inviando al server mentre legge? – deitch

+1

Per prima cosa è necessario eseguire lo streaming del file leggendo blocchi di piccole dimensioni, quindi è sufficiente conservare una parte del file in memoria. Un oggetto file è un'istanza di un oggetto blob, quindi è possibile utilizzare il suo metodo .slice() per creare questi blocchi. – Damien

+0

Bingo. Grazie, @ Damiano – deitch

85

ho fatto in questo modo:

var input = document.querySelector('input[type="file"]') 

var data = new FormData() 
data.append('file', input.files[0]) 
data.append('user', 'hubot') 

fetch('/avatars', { 
    method: 'POST', 
    body: data 
}) 
+5

Non è necessario avvolgere il contenuto del file in un oggetto 'FormData' se tutto ciò che stai caricando è il file (che è ciò che la domanda originale vuole). 'fetch' accetterà' input.files [0] 'come parametro' body'. – Klaus

+3

Se si dispone di un backend PHP che gestisce il caricamento del file, si desidera avvolgere il file in un FormData in modo che l'array $ _FILES sia correttamente compilato. – ddelrio1986

+0

Ho anche notato che Google Chrome non mostrerebbe il file nel carico utile della richiesta senza la parte FormData per qualche motivo. Sembra un bug nel pannello Network di Google Chrome. – ddelrio1986

4

Per inviare un singolo file, è possibile utilizzare semplicemente l'oggetto File dall'array input.files direttamente come valore di body: nel fetch() initializer:

const myInput = document.getElementById('my-input'); 

// Later, perhaps in a form 'submit' handler or the input's 'change' handler: 
fetch('https://example.com/some_endpoint', { 
    method: 'POST', 
    body: myInput.files[0], 
}); 

Questo funziona perché File eredita da Blob, e Blob è uno dei ammissibili BodyInit tipi definiti nel Fetch standard.

+0

Questa è la risposta più semplice ma come 'body: myInput.files [0]' causa la quantità di byte conservati in memoria dal lato client? – bhantol

+1

Mi aspetterei * che con questa soluzione il browser sia sufficientemente sensibile per lo streaming del file e non ne richieda la lettura in memoria, @bhantol, ma non mi sono tolto di mezzo per scoprirlo (empiricamente o scavando nelle specifiche). Se si desidera confermare, è possibile provare (in ciascuno dei principali browser) utilizzando questo approccio per caricare un file da 50 GB o qualcosa del genere e vedere se il browser tenta di utilizzare troppa memoria e viene ucciso. –

Problemi correlati