繁体   English   中英

如何在 Google Cloud Function 的 /tmp 文件夹中下载文件,然后将其上传到 Google Cloud Storage

[英]How to download files in /tmp folder of Google Cloud Function and then upload it in Google Cloud Storage

所以我需要部署一个谷歌云 Function 允许我做两件事。

第一个是在云 Function 的 /tmp 本地目录上的 SFTP/FTP 服务器上下载任何文件。 然后,第二步是将这个文件上传到 Google Cloud Storage 的存储桶中。

实际上我知道如何上传,但我不知道如何从 ftp 服务器下载文件到我的本地 /tmp 目录。

所以,实际上我已经编写了一个 GCF,它接收参数(在主体上)、配置(config)以允许我在 FTP 服务器上连接、文件名和路径。

对于我的测试,我使用了以下 ftp 服务器测试: https://www.sftp.net/public-online-sftp-servers与此配置。

{
    config:
    {
        hostname: 'test.rebex.net',
        username: 'demo',
        port: 22,
        password: 'password'
    },
    filename: 'FtpDownloader.png',
    path: '/pub/example'
}

下载后,我开始上传。 为此,我检查是否在 UPLOAD 之前在 '/tmp/filename' 中找到了 DOWNLOAD 文件,但这里的文件比较紧张。

请参阅以下代码:

exports.transferSFTP = (req, res) =>
{
    let body = req.body;
    if(body.config)
    {
        if(body.filename)
        {
            //DOWNLOAD
            const Client = require('ssh2-sftp-client');
            const fs = require('fs');

            const client = new Client();

            let remotePath
            if(body.path)
                remotePath = body.path + "/" + body.filename;
            else
                remotePath = "/" + body.filename;

            let dst = fs.createWriteStream('/tmp/' + body.filename);

            client.connect(body.config)
            .then(() => {
                console.log("Client is connected !");
                return client.get(remotePath, dst);
            })
            .catch(err => 
                {
                    res.status(500);
                    res.send(err.message);   
                })
           .finally(() => client.end());


           //UPLOAD
            const {Storage} = require('@google-cloud/storage');

            const storage = new Storage({projectId: 'my-project-id'});

            const bucket = storage.bucket('my-bucket-name');

            const file = bucket.file(body.filename);

            fs.stat('/tmp/' + body.filename,(err, stats) =>
            {
                if(stats.isDirectory())
                {
                    fs.createReadStream('/tmp/' + body.filename)
                        .pipe(file.createWriteStream())
                        .on('error', (err) => console.error(err))
                        .on('finish', () => console.log('The file upload is completed !!!'));

                    console.log("File exist in tmp directory");
                    res.status(200).send('Successfully executed !!!')
                }
                else
                {
                    console.log("File is not on the tmp Google directory");
                    res.status(500).send('File is not loaded in tmp Google directory')
                }
            });
        }
        else res.status(500).send('Error: no filename on the body (filename)');
    }
    else res.status(500).send('Error: no configuration elements on the body (config)');
}

因此,我收到以下消息:“文件未加载到 tmp Google 目录中”,因为在 fs.stat() 方法之后,stats.isDirectory() 为 false。 在我使用 fs.stats() 方法检查文件是否在这里之前,我刚刚编写了具有相同文件名但没有内容的文件。 因此,我得出的结论是,我的上传工作,但没有 DONWLOAD 文件,很难将其复制到 Google 云存储中。

感谢您的时间,我希望我能找到解决方案。

问题是在执行上传的代码开始运行之前,您没有等待下载完成。 虽然您确实有一个 catch() 语句,但这还不够。

将第一部分(下载)视为单独的代码块。 您已经告诉 Javascript 到 go 异步执行该块。 一旦您的脚本完成此操作,它就会立即继续执行您的脚本的 rest。 它不会等待“块”完成。 因此,您的上传代码在下载完成之前运行。

你可以做两件事。 第一个是将执行上传的所有代码移动到 get() 调用之后的“then”块中(顺便说一句,您可以使用 fastGet() 来简化事情)。 例如

client.connect(body.config)
 .then(() => {
   console.log("Client is connected !");
   return client.fastGet(remotePath, localPath);
 })
 .then(() => {
    // do the upload
  }) 
  .catch(err => {
     res.status(500);
     res.send(err.message);   
  })
 .finally(() => client.end());

另一种选择是使用 async/await,这将使您的代码看起来更“同步”。 类似于(未经测试)的东西

async function doTransfer(remotePath, localPath) {
  try {
    let client - new Client();
    await client.connect(config);
    await client.fastGet(remotePath, localPath);
    await client.end();
    uploadFile(localPath);
  } catch(err) {
    ....
   }
}

是一个 github 项目,它回答了与您类似的问题。

在这里,他们部署了一个 Cloud Function 从 FTP 下载文件并将它们直接上传到存储桶,跳过了获取临时文件的步骤。

该代码有效,此 github 中的部署方式未更新,因此我将按照我的建议放置部署步骤并验证它们是否有效:

  1. 激活 Cloud Shell 并运行:

  2. 从 github 克隆存储库: git clone https://github.com/RealKinetic/ftp-bucket.git

  3. 切换到目录: cd ftp-bucket

  4. 根据需要调整您的代码

  5. 创建一个 GCS 存储桶,如果您还没有,可以通过gsutil mb -p [PROJECT_ID] gs://[BUCKET_NAME]创建一个

  6. 部署: gcloud functions deploy importFTP --stage-bucket [BUCKET_NAME] --trigger-http --runtime nodejs8

以我个人的经验,这比在两个功能中使用它更有效,除非您需要在同一云 function 中进行一些文件编辑

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM