Как загрузить файлы с URL в облачное хранилище node.js клиент - PullRequest
0 голосов
/ 25 января 2020

В Google Cloud Storage версии 1 я успешно использовал приведенную ниже функцию для загрузки файлов. Он сохраняет файл в уникальном месте во временном каталоге для дальнейшей обработки.

Похоже, что Cloud Storage версии 4 больше не принимает URL в качестве источника. Он будет жаловаться, что файл не существует.

import { File } from "@google-cloud/storage";
import { join, parse } from "path";
import { generate } from "shortid";
import { URL } from "url";
import { getBucket } from "./helpers";

/**
 * This function takes a HTTP URL and uploads it to a destination in the bucket
 * under the same filename or a generated unique name.
 */
export async function uploadFile(
  url: string,
  destinationDir: string,
  options: { generateUniqueFilename: boolean } = {
    generateUniqueFilename: true
  }
): Promise<File> {
  try {
    const pathname = new URL(url).pathname;
    const { ext, base } = parse(pathname);
    let destination = join(destinationDir, base);

    if (options.generateUniqueFilename) {
      const shortId = generate();

      destination = join(destinationDir, `${shortId}${ext}`);
    }

    const bucket = await getBucket();
    const [file] = await bucket.upload(url, {
      destination,
      public: true
    });

    console.log(`Successfully uploaded ${url} to ${destination}`);

    return file;
  } catch (err) {
    throw new Error(
      `Failed to upload ${url} to ${destinationDir}: ${err.message}`
    );
  }
}

Как решить эту проблему с текущей версией? Я не могу найти много информации по этому вопросу. Использование gsutil не вариант для меня. Мне нужно передать URL в облачную функцию и загрузить оттуда.

Ответы [ 2 ]

2 голосов
/ 26 января 2020

Вот что я закончил:

import { File } from "@google-cloud/storage";
import { join, parse } from "path";
import { generate } from "shortid";
import { URL } from "url";
import { getBucket } from "./helpers";
import * as request from "request";

/**
 * This function takes a http url and uploads it to a destination in the bucket
 * under the same filename or a generated unique name.
 */
export async function uploadFile(
  url: string,
  destinationDir: string,
  options: { generateUniqueFilename: boolean } = {
    generateUniqueFilename: true
  }
) {
  console.log("Upload file from", url);
  const pathname = new URL(url).pathname;
  const { ext, base } = parse(pathname);
  let destination = join(destinationDir, base);

  if (options.generateUniqueFilename) {
    const shortId = generate();

    destination = join(destinationDir, `${shortId}${ext}`);
  }

  const bucket = await getBucket();

  return new Promise<File>((resolve, reject) => {
    const file = bucket.file(destination);

    const req = request(url);
    req.pause();
    req.on("response", res => {
      if (res.statusCode !== 200) {
        return reject(
          new Error(
            `Failed to request file from url: ${url}, status code: ${res.statusCode}`
          )
        );
      }

      req
        .pipe(
          file.createWriteStream({
            resumable: false,
            public: true,
            metadata: {
              contentType: res.headers["content-type"]
            }
          })
        )
        .on("error", err => {
          reject(
            new Error(
              `Failed to upload ${url} to ${destinationDir}: ${err.message}`
            )
          );
        })
        .on("finish", () => {
          console.log(`Successfully uploaded ${url} to ${destination}`);
          resolve(file);
        });
      req.resume();
    });
  });
}

2 голосов
/ 25 января 2020

Я думаю, что вы не можете передать URL-адрес непосредственно bucket.upload() Но вы можете загрузить файл и передать его для загрузки, как показано ниже:

import { join, parse } from "path";
import { generate } from "shortid";
import { URL } from "url";
import * as request from "request";
import { getBucket } from "./helpers";
export async function uploadFile(url, destinationDir, options = {
    generateUniqueFilename: true
 }){

    return new Promise(function(resolve, reject) {
        const pathname = new URL(url).pathname;
        const { ext, base } = parse(pathname);
        let destination = join(destinationDir, base);
        let filename;
        if (options.generateUniqueFilename) {
            const shortId = generate();
            filename = `${shortId}${ext}`;
            destination = join(destinationDir, filename);
        }
        let req = request(FILE_URL);
        req.pause();
        req.on('response', res => {
            if (res.statusCode !== 200) {
                reject(new Error("unable to download file from url"));
            }
            const bucket = await getBucket();
            const writeStream = bucket.file(filename)
                .createWriteStream({
                public: true,
                destination,
                metadata: {
                    contentType: res.headers['content-type']
                }
            });
            req.pipe(writeStream);
            req.resume(); // resume when pipe is set up    
            req.on('finish', () => {
                console.log('saved');
                resolve(true);
            });
            req.on('error', err => {
                writeStream.end();
                console.error(err);
                reject(err);
            });
        });
    });
}
...