Я бы взял немного другой подход и вообще не использовал бы локальную файловую систему, поскольку она просто tmpfs и будет стоить вам памяти, которую ваша функция использует в любом случае для хранения буфера / большого двоичного объекта, поэтому проще просто избежать ее изапись непосредственно из этого буфера в GCS с использованием метода save
для объекта файла GCS.
Вот пример. Я упростил многие ваши настройки и использую функцию http вместо вызываемой. Аналогично, я использую общедоступный образ stackoverflow, а не ваши исходные URL. В любом случае вы сможете использовать этот шаблон, чтобы изменить то, что вам нужно (например, изменить прототип, удалить ответ http и заменить его нужным возвращаемым значением):
const functions = require('firebase-functions');
const axios = require('axios');
const admin = require('firebase-admin');
admin.initializeApp();
exports.doIt = functions.https.onRequest((request, response) => {
const bucket = admin.storage().bucket();
const IMAGE_URL = 'https://cdn.sstatic.net/Sites/stackoverflow/company/img/logos/so/so-logo.svg';
const MIME_TYPE = 'image/svg+xml';
return axios.get(IMAGE_URL, { // URL for the image
responseType: 'arraybuffer',
headers: {
accept: MIME_TYPE
}
}).then(response => {
console.log(response); // only to show we got the data for debugging
const destinationFile = bucket.file('my-stackoverflow-logo.svg');
return destinationFile.save(response.data).then(() => { // note: defaults to resumable upload
return destinationFile.setMetadata({ contentType: MIME_TYPE });
});
}).then(() => { response.send('ok'); })
.catch((err) => { console.log(err); })
});
Каккомментатор отметил, что в приведенном выше примере запрос axios сам делает доступ к внешней сети, и для этого вам потребуется план Blaze или Flame. Тем не менее, это само по себе не похоже на вашу текущую проблему.
Аналогично, это также по умолчанию использует возобновляемую загрузку, которую документация не рекомендует, когда вы делаете большое количествомаленький (<10MB файлов), поскольку есть некоторые издержки. </p>
Вы спросили, как это можно использовать для загрузки нескольких файлов. Вот один из подходов. Во-первых, давайте предположим, что у вас есть функция, которая возвращает обещание, которое загружает один файл по его имени (я сократил это из приведенного выше, но оно в основном идентично, за исключением изменения с INPUT_URL
на filename
- обратите внимание, что ононе возвращает окончательный результат, такой как response.send()
, и существует неявное предположение, что все файлы одинаковы MIME_TYPE
):
function downloadOneFile(filename) {
const bucket = admin.storage().bucket();
const MIME_TYPE = 'image/svg+xml';
return axios.get(filename, ...)
.then(response => {
const destinationFile = ...
});
}
Затем вам просто нужно итеративно построить цепочку обещанийиз списка файлов. Допустим, они в imageUrls
. После сборки верните всю цепочку:
let finalPromise = Promise.resolve();
imageUrls.forEach((item) => { finalPromise = finalPromise.then(() => downloadOneFile(item)); });
// if needed, add a final .then() section for the actual function result
return finalPromise.catch((err) => { console.log(err) });
Обратите внимание, что вы также можете создать массив обещаний и передать их в Promise.all()
- это, вероятно, будет быстрее, если вы получите некоторый параллелизм, ноЯ бы не советовал, если вы не уверены, что все данные поместятся в память вашей функции одновременно. Даже при таком подходе необходимо убедиться, что все загрузки могут быть завершены в течение времени ожидания вашей функции.