How to upload an image to Google Cloud Storage from an image url in Node?

后端 未结 6 768
南旧
南旧 2021-02-03 11:33

Given an image url, how can I upload that image to Google Cloud Storage for image processing using Node.js?

6条回答
  •  离开以前
    2021-02-03 12:02

    Leaving my solution here for people who want to use:

    • firebase admin SDK
    • axios and async await
    /**
     * TODO(developer): Uncomment the following lines before running the sample.
     * specify an existing bucket.
     * specify any url pointing to an file.
     */
    // const bucketName = 'liist-prod-nodejs-backend';
    // const url = "https://images.unsplash.com/photo-1601191906024-54b4e490abae?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=800&ixlib=rb-1.2.1&q=80&w=800";
    
    // 1. load required packages
    const axios = require('axios');
    const crypto = require('crypto');
    const httpAdapter = require('axios/lib/adapters/http');
    
    // 2. setup firebase admin SDK + storage bucket
    const admin = require('firebase-admin');
    const serviceAccount = require('path/to/key.json');
    const app = admin.initializeApp({ 
      credential: admin.credential.cert(serviceAccount),
      storageBucket: bucketName
    });
    const storage = app.storage();
    const bucket = storage.bucket(bucketName);
    
    // 3. helper function
    function randomToken(size = 20) { // maxsize is 128
      return crypto.randomBytes(64).toString('hex').substr(0, size)
    }
    
    // 4. async function to actually upload image from link to firebase storage bucket
    async function uploadToStorage(bucket, url) {
      // define filename, folder and access token
      const accessToken = randomToken();
      const bucketName = bucket.name;
      const fileEnding = url.split('.').pop();
      const folder = 'defaultFolder';
      const filename = `myTargetFile`;
      const fullPath = `${folder}/${filename}.${fileEnding}`;
      const fullPathUrlEncoded = `${folder}%2F${filename}.${fileEnding}`;
    
      // axios request to get file stream
      const axiosResponse = await axios.get(url, { responseType: 'stream', adapter: httpAdapter });
      if (axiosResponse.status !== 200) {
        throw new Error(`axios request to ${url} failed.`);
      } 
      // create file + write stream (=> tweak options if needed)
      const file = bucket.file(fullPath);
      const output = file.createWriteStream({
        gzip: true,
        // if public is true, the file can be found here: `https://storage.googleapis.com/${bucketName}/${fullPath}`;
        public: false, // media token needed, more restricted and secure
        metadata: {
          contentType: axiosResponse.headers['content-type'],
          metadata: {
            firebaseStorageDownloadTokens: accessToken, // define access token
          },
        }
      });
      // wrapp stream around a promise
      // => resolves to public url
      const stream = axiosResponse.data;
      const streamPromise = new Promise(function (resolve, reject) {
        stream.on('data', (chunk) => {
          output.write(new Buffer.from(chunk));
        });
        stream.on('end', () => {
          output.end();
          const publicUrl = `https://firebasestorage.googleapis.com/v0/b/${bucketName}/o/${fullPathUrlEncoded}?alt=media&token=${accessToken}`;
          resolve(publicUrl);
        });
        stream.on('error', (err) => {
          output.end();
          reject(err);
        })
      });
      return await streamPromise;
    }
    
    // 4. upload to storage
    console.log("uploading file to storage ...");
    (async () => {
      const publicUrl = await uploadToStorage(bucket, url);
      console.log(publicUrl);
    })(); 
    

提交回复
热议问题