<p>此答案将总结将文件上载到Google/Firebase云存储时获取下载URL的选项。有三种类型的下载URL:</p>
<ol>
<li>已签名下载URL,这些URL是临时的,具有安全功能</li>
<li>令牌下载URL,具有持久性和安全特性</li>
<li>公共下载URL,持久且缺乏安全性</li>
</ol>
<p>有三种方法可以获取令牌下载URL。其他两个下载URL只有一种方法可以获取它们</p>
<p><strong>从Firebase存储控制台</p>
<p>您可以从Firebase存储控制台获取下载URL:</p>
<p><a href="https://i.stack.imgur.com/f61iV.png" rel="noreferrer"><img src="https://i.stack.imgur.com/f61iV.png" alt="enter image description here"/></a></p>
<p>下载URL如下所示:</p>
<pre><code>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
</code></pre>
<p>第一部分是文件的标准路径。最后是代币。此下载URL是永久的,即不会过期,但您可以撤销它</p>
<p><strong>从前端获取下载URL()</strong></p>
<p><a href="https://firebase.google.com/docs/storage/web/download-files" rel="noreferrer">documentation</a>告诉我们使用<code>getDownloadURL()</code>:</p>
<pre class="lang-js prettyprint-override"><code>let url = await firebase.storage().ref('Audio/English/United_States-OED-' + i +'/' + $scope.word.word + ".mp3").getDownloadURL();
</code></pre>
<p>这与您可以从Firebase存储控制台获得的下载URL相同。这种方法很简单,但需要知道文件的路径,在我的应用程序中,对于一个相对简单的数据库结构,大约需要300行代码。如果您的数据库很复杂,这将是一场噩梦。你可以从前端上传文件,但这会让下载你的应用的任何人暴露你的凭证。因此,对于大多数项目,您都希望从节点后端或谷歌云功能上传文件,然后获取下载URL并将其与文件的其他数据一起保存到数据库中</p>
<p><strong>getSignedUrl()用于临时下载URL</strong></p>
<p><a href="https://cloud.google.com/nodejs/docs/reference/storage/2.5.x/File#getSignedUrl" rel="noreferrer">getSignedUrl()</a>易于从节点后端或谷歌云功能使用:</p>
<pre class="lang-js prettyprint-override"><code> 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);
}
});
});
});
});
}
</code></pre>
<p>签名下载URL如下所示:</p>
<pre><code>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
</code></pre>
<p>签名的URL具有过期日期和长签名。命令行<a href="https://cloud.google.com/storage/docs/gsutil/commands/signurl#options" rel="noreferrer">gsutil signurl -d</a>的文档说明,签名URL是临时的:默认过期时间为一小时,最大过期时间为七天</p>
<p>我要在这里大声说<a href="https://cloud.google.com/nodejs/docs/reference/storage/1.5.x/File#getSignedUrl" rel="noreferrer">getSignedUrl</a>从来没有说过你的签名URL将在一周内过期。文档代码将<code>3-17-2025</code>作为过期日期,这表明您可以在将来设置过期年份。我的应用程序工作正常,一周后崩溃了。错误消息说签名不匹配,而不是下载URL已过期。我对我的代码做了各种各样的修改,一切正常……直到一周后全部崩溃。这种情况持续了一个多月的沮丧</p>
<p><strong>公开您的文件</strong></p>
<p>您可以将文件的权限设置为公共读取,如<a href="https://cloud.google.com/storage/docs/access-control/making-data-public" rel="noreferrer">documentation</a>中所述。这可以通过云存储浏览器或节点服务器完成。您可以将一个文件或目录或整个存储数据库公开。以下是节点代码:</p>
<pre class="lang-js prettyprint-override"><code>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));
});
</code></pre>
<p>在云存储浏览器中,结果如下所示:</p>
<p><a href="https://i.stack.imgur.com/V7xzE.png" rel="noreferrer"><img src="https://i.stack.imgur.com/V7xzE.png" alt="enter image description here"/></a></p>
<p>然后,任何人都可以使用标准路径下载您的文件:</p>
<pre><code>https://storage.googleapis.com/languagetwo-cd94d.appspot.com/Audio/English/United_States-OED-0/system.mp3
</code></pre>
<p>另一种公开文件的方法是使用方法<a href="https://googleapis.dev/nodejs/storage/latest/File.html#makePublic" rel="noreferrer">makePublic()</a>。我还没能让它正常工作,要使bucket和文件路径正确是很困难的</p>
<p>一个有趣的替代方法是使用<a href="https://cloud.google.com/storage/docs/access-control/lists" rel="noreferrer">Access Control Lists</a>。您可以使文件仅对您在列表中列出的用户可用,或者使用<code>authenticatedRead</code>使从Google帐户登录的任何人都可以使用该文件。如果有一个选项“任何使用Firebase Auth登录我的应用程序的人”,我会使用这个选项,因为它将仅限制我的用户访问</p>
<p><strong>使用firebaseStorageDownloadTokens构建您自己的下载URL</strong></p>
<p>有几个答案描述了一个未记录的Google存储对象属性<code>firebaseStorageDownloadTokens</code>。有了它,您可以告诉存储您想要使用的令牌。您可以使用<code>uuid</code>节点模块生成令牌。四行代码,您可以构建自己的下载URL,相同的dow从控制台或<code>getDownloadURL()</code>获取的nload URL。这四行代码是:</p>
<pre class="lang-js prettyprint-override"><code>const uuidv4 = require('uuid/v4');
const uuid = uuidv4();
</code></pre>
<pre class="lang-js prettyprint-override"><code>metadata: { firebaseStorageDownloadTokens: uuid }
</code></pre>
<pre class="lang-js prettyprint-override"><code>https://firebasestorage.googleapis.com/v0/b/" + bucket.name + "/o/" + encodeURIComponent('Audio/' + longLanguage + '/' + pronunciation + '/' + word + '.webm') + "?alt=media&token=" + uuid);
</code></pre>
<p>以下是上下文中的代码:</p>
<pre class="lang-js prettyprint-override"><code>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));
});
</code></pre>
<p>这不是打字错误--你必须把<code>firebaseStorageDownloadTokens</code>嵌套在双层<code>metadata:</code>中</p>
<p>Doug Stevenson指出<code>firebaseStorageDownloadTokens</code>不是Google官方的云存储功能。你在谷歌的任何文档中都找不到它,也不能保证它会出现在未来版本的<code>@google-cloud</code>。我喜欢<code>firebaseStorageDownloadTokens</code>,因为这是唯一能得到我想要的东西的方法,但它有一种“气味”,使用起来不安全</p>
<p><strong>为什么没有来自节点的getDownloadURL()?</strong></p>
<p>正如@Clinton所写,谷歌应该在<code>@google-cloud/storage</code>(即,您的节点后端)中创建一个<code>file.getDownloadURL()</code>a方法。我想从谷歌云功能上传一个文件,并获得令牌下载URL</p>