如何通过HTTP Google Cloud功能上传图片文件?

时间:2017-10-01 11:17:27

标签: google-cloud-functions

我已经阅读了有关如何将图像上传到存储桶并通过后台功能进行后期处理的教程。但我的要求是上传图像,进行后处理并立即通过HTTP函数返回结果。如果这是正确的做法,请告诉我,因为我没有在网上获得太多的资料。我是这样做的:

HTTP云功能:

exports.uploadImage = function (req, res){
 var file = req.body.file;
 uploadSomewhere(file)(); < post-processing code which is working fine >

UI表单:

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7/jquery.js"></script> 
<script src="http://malsup.github.com/jquery.form.js"></script>
<form id="myForm" action="<cloud_function_url>/uploadImage" method="post"> 
  <label for="file">Choose file to upload</label>
  <input type="file" id="file" name="file" multiple>
  <input type="submit" value="Submit" /> 
</form>

<script> 
 $(document).ready(function() { 
  $('#myForm').ajaxForm(function() { 
 }); 
}); 
</script>

问题是,在我部署该功能后,当我从存在功能的文件夹上传图像时,图像被上传。但是如果我从任何其他位置上传图像,它会返回错误:

错误:上传图片文件时出错.... - 错误:ENOENT:没有这样的文件或目录,打开'....'

请告诉我我做错了什么或者您是否需要更多信息。

2 个答案:

答案 0 :(得分:1)

此处有https://cloud.google.com/functions/docs/writing/http#multipart_data_and_file_uploads的直接将文件直接上传到Cloud Functions的示例代码,但是请注意,使用此方法时文件大小有限制(10MB)。如果文件大于此大小,建议您使用Cloud Storage方法,并使用Firebase Realtime Database之类的方法来管理客户端上的状态。

因此,您可以使用Cloud Function生成签名的上传URL,然后使用RTDB跟踪客户端的进度。返回URL 对要跟踪进度的数据库位置的引用。客户端将在此位置查看更新。然后,客户端将文件上传到Cloud Storage,并触发第二个功能。在后处理之后,它会更新RTDB,这会将更新下推到客户端。从客户端的角度来看,这都是 synchronous ,但实际上是一系列异步操作,在数据库中具有状态合并。

如果您对文件大小<10MB没问题,以下是从文档中获取的内联更新的示例代码:

/**
 * Parses a 'multipart/form-data' upload request
 *
 * @param {Object} req Cloud Function request context.
 * @param {Object} res Cloud Function response context.
 */
const path = require('path');
const os = require('os');
const fs = require('fs');

// Node.js doesn't have a built-in multipart/form-data parsing library.
// Instead, we can use the 'busboy' library from NPM to parse these requests.
const Busboy = require('busboy');

exports.uploadFile = (req, res) => {
  if (req.method === 'POST') {
    const busboy = new Busboy({ headers: req.headers });
    const tmpdir = os.tmpdir();

    // This object will accumulate all the fields, keyed by their name
    const fields = {};

    // This object will accumulate all the uploaded files, keyed by their name.
    const uploads = {};

    // This code will process each non-file field in the form.
    busboy.on('field', (fieldname, val) => {
      // TODO(developer): Process submitted field values here
      console.log(`Processed field ${fieldname}: ${val}.`);
      fields[fieldname] = val;
    });

    let fileWrites = [];

    // This code will process each file uploaded.
    busboy.on('file', (fieldname, file, filename) => {
      // Note: os.tmpdir() points to an in-memory file system on GCF
      // Thus, any files in it must fit in the instance's memory.
      console.log(`Processed file ${filename}`);
      const filepath = path.join(tmpdir, filename);
      uploads[fieldname] = filepath;

      const writeStream = fs.createWriteStream(filepath);
      file.pipe(writeStream);

      // File was processed by Busboy; wait for it to be written to disk.
      const promise = new Promise((resolve, reject) => {
        file.on('end', () => {
          writeStream.end();
        });
        writeStream.on('finish', resolve);
        writeStream.on('error', reject);
      });
      fileWrites.push(promise);
    });

    // Triggered once all uploaded files are processed by Busboy.
    // We still need to wait for the disk writes (saves) to complete.
    busboy.on('finish', () => {
      Promise.all(fileWrites)
        .then(() => {
          // TODO(developer): Process saved files here
          for (const name in uploads) {
            const file = uploads[name];
            fs.unlinkSync(file);
          }
          res.send();
        });
    });

    busboy.end(req.rawBody);
  } else {
    // Return a "method not allowed" error
    res.status(405).end();
  }
};

答案 1 :(得分:0)

这是功能齐全的功能文件

    const vision = require('@google-cloud/vision')({
        projectId: "pid",
        keyfileName: 'keyfile.json'
    });


    // The Cloud Functions for Firebase SDK to create Cloud Functions and setup triggers.
    const functions = require('firebase-functions');

    // The Firebase Admin SDK to access the Firebase Realtime Database.
    const admin = require('firebase-admin');
    admin.initializeApp();
    // Create the Firebase reference to store our image data
    const db = admin.database();
    const { Storage } = require('@google-cloud/storage');
    // Your Google Cloud Platform project ID                                        
    const projectId = 'pid';

    // Creates a client                                                             
    const storage = new Storage({
        projectId: projectId,
    });
    /**
     * Parses a 'multipart/form-data' upload request
     *
     * @param {Object} req Cloud Function request context.
     * @param {Object} res Cloud Function response context.
     */
    const path = require('path');
    const os = require('os');
    const fs = require('fs');

    // Node.js doesn't have a built-in multipart/form-data parsing library.
    // Instead, we can use the 'busboy' library from NPM to parse these requests.
    const Busboy = require('busboy');

    exports.upload = functions.https.onRequest((req, res) => {
        if (req.method !== 'POST') {
            // Return a "method not allowed" error
            return res.status(405).end();
        }
        const busboy = new Busboy({ headers: req.headers });
        const tmpdir = os.tmpdir();

        // This object will accumulate all the fields, keyed by their name
        const fields = {};

        // This object will accumulate all the uploaded files, keyed by their name.
        const uploads = {};

        // This code will process each non-file field in the form.
        busboy.on('field', (fieldname, val) => {
            // TODO(developer): Process submitted field values here
            console.log(`Processed field ${fieldname}: ${val}.`);
            fields[fieldname] = val;
        });

        const fileWrites = [];

        // This code will process each file uploaded.
        busboy.on('file', (fieldname, file, filename) => {
            // Note: os.tmpdir() points to an in-memory file system on GCF
            // Thus, any files in it must fit in the instance's memory.
            console.log(`Processed file ${filename}`);

            const filepath = path.join(tmpdir, filename);
            uploads[fieldname] = filepath;

            const writeStream = fs.createWriteStream(filepath);
            file.pipe(writeStream);

            // File was processed by Busboy; wait for it to be written to disk.
            const promise = new Promise((resolve, reject) => {
                file.on('end', () => {
                    writeStream.end();
                });
                writeStream.on('finish', resolve);
                writeStream.on('error', reject);
            });
            fileWrites.push(promise);
        });

        // Triggered once all uploaded files are processed by Busboy.
        // We still need to wait for the disk writes (saves) to complete.
        busboy.on('finish', () => {
            Promise.all(fileWrites).then(() => {
                // TODO(developer): Process saved files here
                for (const name in uploads) {
                    const file = uploads[name];
                    async function upload2bucket() {
                        var bucketName = 'bname'
                        fileRes = await storage.bucket(bucketName).upload(file);
                        fs.unlinkSync(file);
                        console.log('fileRes',fileRes)
                        console.log(`Finish: Processed file ${file}`);
                        res.send(fileRes);
                    }
                    upload2bucket()
                }
            });
        });

        busboy.end(req.rawBody);

    });