如何使用云功能通过签名下载地址删除存储图像?
Posted
技术标签:
【中文标题】如何使用云功能通过签名下载地址删除存储图像?【英文标题】:How to use cloud functions to delete a storage image by signed download url? 【发布时间】:2018-06-17 17:19:39 【问题描述】:我正在使用 firebase 云功能来生成缩略图并将签名的图像 url 存储在 firestore 中:
'use strict';
const functions = require('firebase-functions');
const mkdirp = require('mkdirp-promise');
const gcs = require('@google-cloud/storage')(keyFilename: 'service-account-credentials.json');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
const spawn = require('child-process-promise').spawn;
const path = require('path');
const os = require('os');
const fs = require('fs');
const THUMB_MAX_HEIGHT = 200;
const THUMB_MAX_WIDTH = 200;
const THUMB_PREFIX = 'thumb_';
exports.onUploadImage = functions.storage.object().onChange(async event =>
const filePath = event.data.name;
const contentType = event.data.contentType;
const fileDir = path.dirname(filePath);
const fileName = path.basename(filePath);
const thumbFilePath = path.normalize(path.join(fileDir, `$THUMB_PREFIX$fileName`));
const tempLocalFile = path.join(os.tmpdir(), filePath);
const tempLocalDir = path.dirname(tempLocalFile);
const tempLocalThumbFile = path.join(os.tmpdir(), thumbFilePath);
if (!contentType.startsWith('image/'))
return null;
if (fileName.startsWith(THUMB_PREFIX))
return null;
if (event.data.resourceState === 'not_exists')
return null;
const tankId = event.data.metadata.tankId;
const userId = event.data.metadata.userId;
const imageType = event.data.metadata.type;
const bucket = gcs.bucket(event.data.bucket);
const file = bucket.file(filePath);
const thumbFile = bucket.file(thumbFilePath);
const metadata =
contentType: contentType,
customMetadata:
'type': imageType
;
try
await mkdirp(tempLocalDir);
await file.download(destination: tempLocalFile);
await spawn('convert', [tempLocalFile, '-thumbnail', `$THUMB_MAX_WIDTHx$THUMB_MAX_HEIGHT>`, tempLocalThumbFile], capture: ['stdout', 'stderr']);
await bucket.upload(tempLocalThumbFile, destination: thumbFilePath, metadata: metadata );
await fs.unlinkSync(tempLocalFile);
await fs.unlinkSync(tempLocalThumbFile);
const config =
action: 'read',
expires: '03-01-2500'
;
const results = await Promise.all([
thumbFile.getSignedUrl(config),
file.getSignedUrl(config)
]);
const thumbResult = results[0];
const originalResult = results[1];
const thumbFileUrl = thumbResult[0];
const fileUrl = originalResult[0];
const tankRef = admin.firestore().collection('tanks').doc(tankId);
switch(imageType)
case 'gallery':
await tankRef
.collection('gallery')
.add(
url: fileUrl,
thumbnail: thumbFileUrl,
createdAt: new Date()
);
const tankSnapshot = await tankRef.get();
const tankData = await tankSnapshot.data();
let galleryCount = tankData.galleryCount || 0;
galleryCount += 1;
if (galleryCount < 0) galleryCount = 0;
return await tankRef.update( galleryCount , merge: true );
case 'tankImage':
await tankRef.set( image: fileUrl, image_thumb: thumbFileUrl , merge: true );
return null;
case 'profileImage':
await admin.auth().updateUser(userId, photoURL: thumbFileUrl );
await admin.firestore()
.collection('users')
.doc(userId)
.set(image: fileUrl);
return null;
default:
return null
catch(err)
console.log(err);
);
现在我正在尝试编写另一个云函数,当 firestore db 条目被删除时,它会从存储桶中删除存储的文件:
exports.onGalleryImageDelete = functions.firestore
.document('/tanks/tankId/gallery/docId')
.onDelete(async event =>
const deletedDoc = event.data.previous.data();
const bucket = admin.storage().bucket();
await bucket.file(deletedDoc.url).delete(); // this is wrong... no idea how to solve this
await bucket.file(deletedDoc.thumbnail).delete();
return await updateTankDocumentCounter(event, 'galleryCount', 'onDelete');
);
此代码实际上不起作用并返回一些 API 错误。如何从给定的签名下载 url 中删除这些图像?
【问题讨论】:
您可以在存储中存储路径以及签名的 url。签名的 url 不会帮助您删除文件,但存储路径会。filePath
和 thumbFilePath
.
非常感谢。我已经想到了这一点,但确实希望有更好的解决方案。
【参考方案1】:
根据 Doug Stevenson 的评论,我存储了数据库的路径并最终得到了这个云功能:
exports.onGalleryImageDelete = functions.firestore
.document('/tanks/tankId/gallery/docId')
.onDelete(async event =>
const deletedDoc = event.data.previous.data();
const filePath = deletedDoc.path;
const fileDir = path.dirname(filePath);
const fileName = path.basename(filePath);
const thumbFilePath = path.normalize(path.join(fileDir, `$THUMB_PREFIX$fileName`));
const bucket = admin.storage().bucket();
return await Promise.all([
await bucket.file(filePath).delete(),
await bucket.file(thumbFilePath).delete(),
updateTankDocumentCounter(event, 'galleryCount', 'onDelete')
]);
);
【讨论】:
【参考方案2】:我也遇到了这个问题。结果返回一个存储所有隐藏信息的文档。 如果 Firebase 有什么好的,其他的就很差了。
【讨论】:
以上是关于如何使用云功能通过签名下载地址删除存储图像?的主要内容,如果未能解决你的问题,请参考以下文章
如何从 Firebase 存储下载 URL 中删除查询字符串