概要
フロント側からFirebase SDKを利用して画像をアップロードするのではなく、サーバー側でFirebase Admin SDKを利用して画像を直接アップロードする方法に関して試行錯誤したので、備忘録として残す
前提
Firebase SDKで画像をアップロードするには
以下の公式ドキュメントに書かれているように、Firebas SDKを利用して、Blob, File,バイト配列など様々な形式からファイルをアップロードすることができる
ただし、サーバー側ではFirebase SDKは使えず、Firebase Admin SDKを利用する必要がある
// Fileからアップロードする例
async uploadFile(file: File) {
const path = 'cloud_storage_path';
try {
const ref = this.$firebase.storage().ref();
const imgRef = ref.child(path);
await imgRef.put(file);
} catch (err) {
console.error(err);
alert('画像のアップロードに失敗しました');
}
}
}
Firebase Admin SDKで画像をアップロードするには
Firebase Admin SDKでは
という2つの方法がある
今回はローカルに一時ファイルを作成せずに、直接アップロードする方法を採用する
Firebase Admin SDKでGoogle Cloud Storageに直接ファイルをアップロードする方法
結果としては以下のコードで直接ファイルをアップロードを実現できた
サーバー側
async uploadFile(content: StorageUploadContent) {
try {
const bucket = admin.storage().bucket('bucket_name');
const file = bucket.file('cloud_storage_path');
const buffer = Buffer.from(content.file, 'base64');
await file.save(buffer, {
metadata: {
contentType: content.type,
},
});
} catch (err) {
console.error(err);
throw err;
}
}
フロント側
async uploadFile(file: File) {
const path = 'cloud_storage_path';
const reader = new FileReader();
reader.onload = async () => {
const arrayBuffer = new Uint8Array(reader.result as ArrayBuffer);
// ArrayBufferからbase64文字列に変換
const base64 = btoa(
arrayBuffer.reduce((p, c) => {
return p + String.fromCharCode(c);
}, '')
);
const content: StorageUploadContent = { file: base64, type: file.type, path };
try {
// 自前で作成したAPIを叩く
await this.$storage.uploadContent(content);
} catch (err) {
console.error(err);
alert('画像のアップロードに失敗しました');
}
};
await reader.readAsArrayBuffer(file);
}
詰まったところ
File型ではFile.save()ができない
Firebase SDK同様にFile型をそのまま渡してアップロードしようとしていたが、
TypeError: The "chunk" argument must be one of type string or Buffer. Received type object...
というエラーが出るので、File型ではアップロードができない
File型をバイナリ文字列でアップロードすると画像がうまく保存されない
File型をFileReader.readAsBinaryString()でバイナリ文字列に変換してアップロードしたところ、アップロードには成功するが画像が表示されない
File型をbase64文字列でアップロードすると画像がうまく保存されない
バイナリ文字列に変換した場合と同様の結果となった
must be one of type string
とはどんな文字列なんだろか?
結果としてはbase64文字列をフロント側から渡して、サーバー側でデコードしてFile.save()に渡すようにした