本答案将总结上传文件到Google / Firebase Cloud Storage时获取下载URL的选项。有三种类型的下载URLS:
1.持久且具有安全功能的{{令牌}}下载URLS
2.临时且具有安全功能的{{已签名}}下载URLS
3.持久且缺乏安全性的{{公共}}下载URLS
有两种方法可以获得{{令牌}}下载URL。{{已签名}}和{{公共}}下载URL各有一种获取方式。
{{令牌}} URL方法#1:从Firebase Storage控制台
您可以从Firebase Storage控制台获取下载URL:
![enter image description here](https://istack.dev59.com/f61iV.webp)
下载链接看起来像这样:
{{下载URL}}
https://firebasestorage.googleapis.com/v0/b/languagetwo-cd94d.appspot.com/o/Audio%2FEnglish%2FUnited_States-OED-0%2Fabout.mp3?alt=media&token=489c48b3-23fb-4270-bd85-0a328d2808e5
第一部分是指向您文件的标准路径。末尾是令牌。这个下载URL是永久的,即它不会过期,尽管您可以撤销它。
令牌URL方法#2:从前端
文档告诉我们要使用getDownloadURL()
:
let url = await firebase.storage().ref('Audio/English/United_States-OED-' + i +'/' + $scope.word.word + ".mp3").getDownloadURL();
这将获取与您从Firebase Storage控制台获取的相同的下载URL。这种方法很容易,但需要您知道文件的路径,在我的应用程序中这很困难。您可以从前端上传文件,但这会使下载您的应用程序的任何人都能看到您的凭据。因此,对于大多数项目,您将希望从Cloud Functions上传文件,然后获取下载URL并将其保存到数据库中,以及有关文件的其他数据。
当我从Cloud Function写入文件到Storage时(因为我找不到一种方法来告诉前端文件已写入Storage),我找不到获取令牌下载URL的方法,但对我有效的方法是将文件写入公开可用的URL,将公开可用的URL写入Firebase,然后当我的Angular前端从Firebase获取下载URL时,它也运行getDownloadURL()(其中包含令牌),然后将Firestore中的下载URL与令牌下载URL进行比较,如果它们不匹配,则在Firestore中将令牌下载URL更新为公开可用URL。这只会将您的文件公开一次。
这比听起来要容易得多。以下代码遍历存储下载URL数组,并使用令牌下载URL替换公开可用的下载URL。
const storage = getStorage();
var audioFiles: string[] = [];
if (this.pronunciationArray[0].pronunciation != undefined) {
for (const audioFile of this.pronunciationArray[0].audioFiles) {
let url = await getDownloadURL(ref(storage, audioFile));
if (audioFile !== url) {
audioFiles.push(url);
}
};
if (audioFiles.length > 0) {
await updateDoc(doc(this.firestore, 'Dictionaries/' + this.l2Language.long + '/Words/' + word + '/Pronunciations/', this.pronunciationArray[0].pronunciation), {
audioFiles: audioFiles
});
}
}
你可能会想,“我将从我的云函数返回存储位置到前端,然后使用
getDownloadURL()
与Firestore一起写入令牌下载URL。”这样做不起作用,因为云函数只能返回同步结果。异步操作会返回
null
。
你可能会说:“没问题,我将在Storage上设置一个Observer,从Observer获取位置,然后使用
getDownloadURL()
将位置与Firestore一起写入令牌下载URL。” 不行,Firestore有观察者,但Storage没有。
你可能会说:“那我从前端调用
listAll(),获取所有Storage文件的列表,然后调用每个文件的
metadata,并提取每个文件的下载URL和令牌,然后将它们写入Firestore?”很好的尝试,但是Storage元数据不包括下载URL或令牌。
签名URL方法#1:用于临时下载URL的getSignedUrl()
从云函数中使用
getSignedUrl()很容易:
function oedPromise() {
return new Promise(function(resolve, reject) {
http.get(oedAudioURL, function(response) {
response.pipe(file.createWriteStream(options))
.on('error', function(error) {
console.error(error);
reject(error);
})
.on('finish', function() {
file.getSignedUrl(config, function(err, url) {
if (err) {
console.error(err);
return;
} else {
resolve(url);
}
});
});
});
});
}
签署的下载URL如下所示:
https://storage.googleapis.com/languagetwo-cd94d.appspot.com/Audio%2FSpanish%2FLatin_America-Sofia-Female-IBM%2Faqu%C3%AD.mp3?GoogleAccessId=languagetwo-cd94d%40appspot.gserviceaccount.com&Expires=4711305600&Signature=WUmABCZIlUp6eg7dKaBFycuO%2Baz5vOGTl29Je%2BNpselq8JSl7%2BIGG1LnCl0AlrHpxVZLxhk0iiqIejj4Qa6pSMx%2FhuBfZLT2Z%2FQhIzEAoyiZFn8xy%2FrhtymjDcpbDKGZYjmWNONFezMgYekNYHi05EPMoHtiUDsP47xHm3XwW9BcbuW6DaWh2UKrCxERy6cJTJ01H9NK1wCUZSMT0%2BUeNpwTvbRwc4aIqSD3UbXSMQlFMxxWbPvf%2B8Q0nEcaAB1qMKwNhw1ofAxSSaJvUdXeLFNVxsjm2V9HX4Y7OIuWwAxtGedLhgSleOP4ErByvGQCZsoO4nljjF97veil62ilaQ%3D%3D
已签名的URL具有过期日期和长签名。命令行
gsutil signurl -d的文档说明签名URL是临时的:默认过期时间为一小时,最大过期时间为七天。
我要在这里发牢骚,
getSignedUrl文档从未说过您的已签名URL将在一周内过期。文档代码将
3-17-2025
作为到期日期,表明您可以将有效期设置为未来几年。我的应用程序完美地运行了一段时间,然后在一周后崩溃了。错误消息说签名不匹配,而不是下载URL已过期。我对我的代码进行了各种更改,一切都正常...直到一周后又崩溃了。这种情况持续了一个多月的挫折。
3-17-2025
日期是否是内部玩笑?就像在视线中看不到小矮人时消失的金币一样,未来数年的圣帕特里克节到期日在两周后消失,就在您认为您的代码没有漏洞时。
公共URL#1:使您的文件公开可用。
您可以按照文档中的说明将文件权限设置为公共读取。这可以通过Cloud Storage浏览器或Node服务器完成。您可以使一个文件公开,也可以使目录或整个存储数据库公开。以下是Node代码:
var webmPromise = new Promise(function(resolve, reject) {
var options = {
destination: ('Audio/' + longLanguage + '/' + pronunciation + '/' + word + '.mp3'),
predefinedAcl: 'publicRead',
contentType: 'audio/' + audioType,
};
synthesizeParams.accept = 'audio/webm';
var file = bucket.file('Audio/' + longLanguage + '/' + pronunciation + '/' + word + '.webm');
textToSpeech.synthesize(synthesizeParams)
.then(function(audio) {
audio.pipe(file.createWriteStream(options));
})
.then(function() {
console.log("webm audio file written.");
resolve();
})
.catch(error => console.error(error));
});
你在云存储浏览器中看到的结果将是这样的:
![enter image description here](https://istack.dev59.com/V7xzE.webp)
任何人都可以使用标准路径下载您的文件:
https://storage.googleapis.com/languagetwo-cd94d.appspot.com/Audio/English/United_States-OED-0/system.mp3
另一种使文件公开的方法是使用makePublic()方法。我无法让它起作用,很难正确获取存储桶和文件路径。
一个有趣的替代方法是使用访问控制列表。您可以仅将文件提供给您列出的用户,或使用authenticatedRead
使文件对从Google帐户登录的任何人都可用。如果有一个“任何使用Firebase Auth登录我的应用程序的人”选项,我会使用它,因为它只限制对我的用户的访问。
已弃用:使用firebaseStorageDownloadTokens构建自己的下载URL
几个答案描述了一个未记录在Google Storage对象属性中的firebaseStorageDownloadTokens
。这从未是官方的Google Cloud Storage功能,现在已不再起作用。以下是它的工作方式。
您告诉Storage要使用的令牌。然后,您使用uuid
Node模块生成令牌。四行代码,您就可以构建自己的下载URL,与控制台或getDownloadURL()
获得的相同的下载URL。这四行代码是:
const uuidv4 = require('uuid/v4');
const uuid = uuidv4();
metadata: { firebaseStorageDownloadTokens: uuid }
https:
以下是上下文中的代码:
var webmPromise = new Promise(function(resolve, reject) {
var options = {
destination: ('Audio/' + longLanguage + '/' + pronunciation + '/' + word + '.mp3'),
contentType: 'audio/' + audioType,
metadata: {
metadata: {
firebaseStorageDownloadTokens: uuid,
}
}
};
synthesizeParams.accept = 'audio/webm';
var file = bucket.file('Audio/' + longLanguage + '/' + pronunciation + '/' + word + '.webm');
textToSpeech.synthesize(synthesizeParams)
.then(function(audio) {
audio.pipe(file.createWriteStream(options));
})
.then(function() {
resolve("https://firebasestorage.googleapis.com/v0/b/" + bucket.name + "/o/" + encodeURIComponent('Audio/' + longLanguage + '/' + pronunciation + '/' + word + '.webm') + "?alt=media&token=" + uuid);
})
.catch(error => console.error(error));
});
这不是打错了--你需要将firebaseStorageDownloadTokens
嵌套在metadata:
的双层中!