web-dev-qa-db-ja.com

ファイルアップロード用のFirebaseクラウド機能

Googleクラウドストレージにファイルをアップロードするために書いたこのクラウド機能があります:

const gcs = require('@google-cloud/storage')({keyFilename:'2fe4e3d2bfdc.json'});

var filePath = file.path + "/" + file.name;

    return bucket.upload(filePath, {
        destination: file.name
    }).catch(reason => {
            console.error(reason);
    });

formidableを使用してアップロードされたファイルを解析し、アップロードされたファイルのプロパティを記録しようとしましたが、問題ないようです。一時ディレクトリにアップロードされます'/tmp/upload_2866bbe4fdcc5beb30c06ae6c3f6b1aa/しかし、ファイルをgcsにアップロードしようとすると、次のエラーが発生します。

{ Error: EACCES: permission denied, stat '/tmp/upload_2866bbe4fdcc5beb30c06ae6c3f6b1aa/thumb_ttttttt.jpg'
    at Error (native)
  errno: -13,
  code: 'EACCES',
  syscall: 'stat',
  path: '/tmp/upload_2866bbe4fdcc5beb30c06ae6c3f6b1aa/thumb_ttttttt.jpg' }

このhtmlフォームを使用してファイルをアップロードしています。

<!DOCTYPE html>
<html>
<body>

<form action="https://us-central1-appname.cloudfunctions.net/uploadFile" method="post" enctype="multipart/form-data">
    Select image to upload:
    <input type="file" name="fileToUpload" id="fileToUpload">
    <input type="submit" value="Upload Image" name="submit">
</form>

</body>
</html>
14
dsharew

Firebase Support Teamから解決策を得ました

まず、このコードには、「整形可能な」ライブラリの小さな誤解が含まれています。この線:

_var filePath = file.path + "/" + file.name;
_

は、「formidable」が元の名前でファイルをアップロードし、ランダムな名前で一時ディレクトリに保存することを期待していることを示します。実際、「formidable」は、「file.path」に保存されているランダムなパスにファイルをアップロードし、元のファイル名をまったく使用しません。必要に応じて、「file.name」を読み取ることにより、元のファイル名が何であるかを確認できます。

したがって、コードの簡単な修正は変更することです。

_var filePath = file.path + "/" + file.name;
_

ただ:

_var filePath = file.path;
_

第二に、このコードのトラブルを引き起こす可能性のあるもう1つの問題があります。「form.parse(...)」で行われた非同期作業が完了する前に、関数が終了します。つまり、実際のファイルのアップロードは、関数が既に完了したと言っているときに発生する可能性があるため、CPUやメモリが予約されていないため、アップロードが非常に遅くなるか、失敗することさえあります。

そのための修正は、form.parse(...)をpromiseでラップすることです:

_exports.uploadFile = functions.https.onRequest((req, res) => {
   var form = new formidable.IncomingForm();
   return new Promise((resolve, reject) => {
     form.parse(req, function(err, fields, files) {
       var file = files.fileToUpload;
       if(!file){
         reject("no file to upload, please choose a file.");
         return;
       }
       console.info("about to upload file as a json: " + file.type);
       var filePath = file.path;
       console.log('File path: ' + filePath);

       var bucket = gcs.bucket('bucket-name');
       return bucket.upload(filePath, {
           destination: file.name
       }).then(() => {
         resolve();  // Whole thing completed successfully.
       }).catch((err) => {
         reject('Failed to upload: ' + JSON.stringify(err));
       });
     });
   }).then(() => {
     res.status(200).send('Yay!');
     return null
   }).catch(err => {
     console.error('Error while parsing form: ' + err);
     res.status(500).send('Error while parsing form: ' + err);
   });
 });
_

最後に、ファイルをアップロードする際に、クラウド機能の代わりにCloud Storage for Firebaseの使用を検討することもできます。 Cloud Storage for Firebaseを使用すると、ファイルを直接ファイルにアップロードできます。
アクセス制御があります
再開可能なアップロード/ダウンロードがあります(接続性が悪い場合に最適)
タイムアウトの問題なしに任意のサイズのファイルを受け入れることができます
ファイルのアップロードに応じてクラウド機能を実行する必要がある場合は、それ以上のことができます

14
dsharew

これをdownloadingでファイルをtmpに代わりに管理しました。

必要になるだろう:

const mkdirp = require('mkdirp-promise');

次に、onChange内。私はtempLocalDirを次のように作成しました:

const LOCAL_TMP_FOLDER = '/tmp/';
const fileDir = (the name of the file); //whatever method you choose to do this
const tempLocalDir = `${LOCAL_TMP_FOLDER}${fileDir}`;

次に、mkdirpを使用して一時ディレクトリを作成します

return mkdirp(tempLocalDir).then(() => {
// Then Download file from bucket.
const bucket = gcs.bucket(object.bucket);
return bucket.file(filePath).download({
  destination: tempLocalFile
}).then(() => {
    console.log('The file has been downloaded to', tempLocalFile);
    //Here I have some code that converts images then returns the converted image
    //Then I use
    return bucket.upload((the converted image), {
        destination: (a file path in your database)
    }).then(() => {
        console.log('JPEG image uploaded to Storage at', filePath);
    })//You can perform more actions of end the promise here

私のコードは、あなたが達成しようとしていたことを達成したと思います。これがお役に立てば幸いです。必要に応じて、より多くのコードを提供できます。

1
Drei