2016-03-17 12 views
57

私はまだそれの周りに私の頭をラップしようとしています。JSフェッチAPIを使用してファイルをアップロードするにはどうすればよいですか?

私は、ファイル入力でユーザーがファイル(あるいは複数)を選択することができます:

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

をそして私は<fill in your event handler here>を使用してsubmitイベントをキャッチすることができます。しかし、いったんやりますと、fetchを使ってファイルを送信するにはどうすればよいですか?

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

答えて

36

これは、upload関数は何をlookigされ、基本的例をコメントです:送信するには

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 
}) 
+1

私は近くにいましたが、かなりありませんでした。大きなファイルではどうしますか?これはブラウザのメモリにすべてロードされているのでしょうか、それとも読み込み時にサーバーに送信していますか? – deitch

+1

まず、小さいサイズのチャンクを読み込んでファイルをストリーミングする必要があります。そのため、ファイルの一部をメモリに保持するだけです。ファイルオブジェクトはBlobオブジェクトのインスタンスなので、.slice()メソッドを使用してこれらのチャンクを作成できます。 – Damien

+0

ビンゴ。ありがとう、@ダミアン – deitch

85

単一ファイルの場合、input.files配列のFileオブジェクトをそのままの値として使用することができますあなたのfetch()初期化子で10:

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], 
}); 

FileBlobから継承し、Blobフェッチ規格で定義された許容BodyInit種類の一つであるので、これは動作します。

+5

アップロードしているすべてがファイル(元の質問が望むもの)であれば、ファイルの内容を 'FormData'オブジェクトにラップする必要はありません。 'fetch'は上記の' body'パラメータとして 'input.files [0]'を受け入れます。 – Klaus

+3

PHPのバックエンドでファイルのアップロードを処理している場合は、$ _FILES配列が適切に設定されるようにFormDataにファイルをラップします。 – ddelrio1986

+0

何らかの理由でGoogle ChromeがFormData部分のないリクエストペイロードにファイルを表示しないことにも気付きました。 Google Chromeのネットワークパネルのバグのようです。 – ddelrio1986

4

:私はこのようにそれをやった

// 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); 
+0

これは最も簡単な答えですが、 'body:myInput.files [0]'はクライアント側でメモリに保持されるバイト数をどのようにしますか? – bhantol

+1

このソリューションでは、ブラウザを使用すると、ファイルをストリーミングしてメモリに読み込む必要はありませんが、私は見つけ出すことができませんでした(経験的にも、仕様に掘り下げて)。あなたが確認したいのであれば、このアプローチを使って(各主要ブラウザで)50GBのファイルをアップロードして、ブラウザがあまりにも多くのメモリを使いこなして死に至らないかどうかを調べることができます。 –

関連する問題