Closed3
「ブラウザからファイルアップロードする際にプログレスバーを表示したい」調べたことまとめ
一番カンタンな方法
axiosの第3引数にoptionを渡す。コードはaxiosのgithubから抜粋
document.getElementById('upload').onclick = function () {
var data = new FormData();
data.append('foo', 'bar');
data.append('file', document.getElementById('file').files[0]);
var config = {
onUploadProgress: function(progressEvent) {
var percentCompleted = Math.round( (progressEvent.loaded * 100) / progressEvent.total );
}
};
axios.put('/upload/server', data, config)
.then(function (res) {
output.className = 'container';
output.innerHTML = res.data;
})
.catch(function (err) {
output.className = 'container text-danger';
output.innerHTML = err.message;
});
};
websocketを使った方法
僕自身が実現したかったのは、websocketを使ってファイルをアップロードする際に、プログレスバーを表示したかったです。
調べたところ以下のstackoverflowが詳しかったです。
結論からいうと、websocketを利用して、onUploadProgress
のような進捗コールバックを取得するよい方法はなさげです。そこで上記のstackoverflowは次のような提案をしていました。
- ファイルアップロードはwebsocketではなくHTTPリクエスト(axiosなど)を利用する
- 次のようにフロントでFileもしくはBlobをsliceして分割アップロードする。サーバー側ではアップロード完了次第終わったことをemitし、フロントに告げる。フロントは終わったことを知って、次のアップロードをする。
function Uploader(url, file) {
var fs = new FileSlicer(file);
var socket = new WebSocket(url);
socket.onopen = function() {
socket.send(fs.getNextSlice());
}
socket.onmessage = function(ms){
if(ms.data=="ok"){
fs.slices--;
if(fs.slices>0) socket.send(fs.getNextSlice());
}else{
// handle the error code here.
}
}
}
上記のコードはstackoverflowから持ってきました。ここでのFileSlicerはどのような実装かは述べられていませんでした...。
あと、File.sliceというメソッドがちらほら検索にひっかかるけど、探しても出てこないので、一旦Blobにしてからblob.sliceをしないといけないかもしれません。
追記:
すみません、File..sliceというメソッドがないみたいな嘘ついてしまいました。ありました。
どうやらBlobから継承しているみたいです。
AWS S3を使った方法
aws-sdk をつかってブラウザからアップロードする状況を考えます。
AWS.S3.managedUploadを使うと実現できるみたいです。AWS.S3.uploadという構文もあるみたいです。
コードの検証はしてません。
function addPhoto(albumName) {
var files = document.getElementById("photoupload").files;
if (!files.length) {
return alert("Please choose a file to upload first.");
}
var file = files[0];
var fileName = file.name;
var albumPhotosKey = encodeURIComponent(albumName) + "/";
var photoKey = albumPhotosKey + fileName;
// Use S3 ManagedUpload class as it supports multipart uploads
var upload = new AWS.S3.ManagedUpload({
params: {
Bucket: albumBucketName,
Key: photoKey,
Body: file,
ACL: "public-read"
}
});
サンプルコードをコメントアウト
// var promise = upload.promise();
おそらくここを次のようにすれば取得できそう
var promise = upload.on('httpUploadProgress', (progress) => {
console.log("Uploaded :: " + parseInt((progress.loaded * 100) / progress.total)+'%');
}).promise();
promise.then(
function(data) {
alert("Successfully uploaded photo.");
viewAlbum(albumName);
},
function(err) {
return alert("There was an error uploading your photo: ", err.message);
}
);
}
ドキュメントによれば、このhttpUploadProgress
イベントは複数のアップロードをまとめて一つのイベントにしているみたいです。
このスクラップは2020/12/03にクローズされました