在本章中,我们将讨论 Firebase 的云存储及其与 Google 云平台的集成。我们还将探讨 Firebase 托管,它允许您在生产级环境中托管 web 应用程序和静态内容(CDN)。
云存储提供了可扩展且安全的对象存储空间,因为当今大多数企业都需要可扩展的文件存储,因为它们通过移动应用程序、web 应用程序或公司网站收集了大量数据。即使是部署在云上的应用程序也需要存储空间来存储自己的资产,如图像、JavaScript、CSS、音频、视频文件,或用户生成的内容,如文档、视频或音频。
Firebase SDK for Cloud Storage 使用 Google 云存储桶存储上传的文件。谷歌云平台需要一个计费帐户来使用其产品,尽管它们提供了一些试用版。Firebase SDK for Cloud storage 在 Google App Engine 免费层中使用默认 bucket,因此您不需要计费帐户。一旦你的应用开始增长,你还可以将其他产品和服务(如托管计算)集成为应用引擎或云函数。
以下是我们将在本章中介绍的主题列表:
- 谷歌云存储概述
- 谷歌云存储的关键特性
- Google 云存储支持的存储类
- 谷歌云存储安全及访问控制列表****ACL概述
- Firebase 云存储的关键功能
- 云存储的设置
- 将 Firebase 云存储与帮助台应用程序集成,以上载和下载文件
- 谷歌应用引擎概述
- Firebase 托管概述
- 在 Firebase 主机上部署帮助台应用程序前端
在深入探讨 Firebase 的云存储之前,让我们先讨论一下 Google 云存储及其功能。
谷歌云平台提供了一个安全、可扩展、经济高效、高性能的基础设施,其中包括开发、管理和操作应用程序所需的各种服务。谷歌云存储是谷歌云平台的一部分,这是一个一站式解决方案,可满足您的所有对象存储需求,从存储到实时流媒体,从分析到归档,它涵盖了所有方面。对象存储是一种大规模可扩展且经济高效的存储服务,用于以其本机格式存储任何类型的数据。
针对不同的存储需求,谷歌云存储提供了不同类别的存储,即多区域存储、区域存储、近线存储和冷线存储。
谷歌云存储在以下关键领域提供了优势:
- **耐久性:**谷歌云存储旨在提供 99.99999999%的年耐久性。数据是冗余存储的。上载数据时,它会在后台通过自动校验和进行复制,以确保数据完整性。
- **可用:**谷歌云存储提供高可用性,让您的数据在需要时随时可用。根据谷歌云存储文档,在服务级别协议中,多区域提供 99.95%的月可用性,区域存储提供 99.9%的月可用性。近线存储和冷线存储每月提供 99%的可用性。
- **可扩展性:**谷歌云存储的可扩展性是无限的,因此它可以支持从小型到 EB 级的系统。
- **一致性:**谷歌云存储确保了写后读的一致性,这意味着如果一次写入成功,任何 GET 请求都会在全局范围内返回文档的最新副本。这适用于新对象或覆盖对象的
DELETE或PUT。 - **安全:**谷歌云存储高度安全,具有谷歌级安全性,可保护您最关键的文档、媒体和资产。它还提供了不同的访问控制选项,以便您可以控制谁有权访问存储对象以及访问级别。
- **易用性:**谷歌云存储提供简单易用的 API 和实用工具来处理对象存储。
我们需要了解谷歌云存储的一些基本概念,才能有效地使用它。那么,让我们看看这里:
云存储中的所有数据都属于一个项目。一个项目由 API、一组用户以及安全和监控设置组成。您可以创建任意数量的项目。在项目内部,我们有称为 bucket 的数据容器,它将上传的数据作为对象保存。对象只不过是一个文件和一些描述该文件的元数据(可选)。
bucket 是保存数据的容器。它们类似于计算机文件系统中的目录,是放置数据的基本容器。唯一的区别是,与目录不同,不能嵌套 bucket。你放在云存储中的所有东西都必须放在一个桶里。Bucket 允许您组织数据,还允许您控制对数据的访问权限。在设计应用程序时,在大多数情况下,由于 bucket 创建和删除的速率限制,您应该计划更少的 bucket 和更多的对象。每个项目大约每 2 秒进行一次操作。
创建 bucket 时需要指定三件事:全局唯一名称、默认存储类以及存储 bucket 及其内容的地理位置。如果在存储对象时未明确指定对象类,则选择的默认存储类将应用于该 bucket 内的对象。
一旦创建了 bucket,就不能更改 bucket 的名称及其位置,除非删除并重新创建它。但是,您可以将其默认存储类更改为 bucket 位置中可用的任何其他类。
Bucket 名称应该是全局唯一的,并且可以与 CNAME 重定向一起使用。
您的 bucket 名称必须满足以下要求:
- 它只能包含小写字母、数字和特殊字符:破折号(-)、下划线(_)和点()。包含点的名称需要验证。
- 它必须以数字或字母开头和结尾。
- 长度必须为 3 到 63 个字符。包含点的名称的长度可以是 222 个字符,但每个点分隔的组件的长度不得超过 63 个字符。
- 它不能表示 IP 地址,如
192.168.1.1。 - 它不能以“goog”前缀开头,也不能包含谷歌或谷歌拼写错误。
除了名称之外,还可以将称为 bucket 标签的键值元数据对与 bucket 相关联。Bucket 标签允许您将 Bucket 与其他 Google 云平台服务(如虚拟机实例和持久磁盘)分组。每个存储桶最多可以有 64 个存储桶标签。
对象是存储在云存储中的基本实体。您可以在一个 bucket 中存储无限多的对象,因此本质上没有限制。
对象由对象数据和对象元数据组成。对象数据通常是一个文件,对云存储是不透明的(一块数据)。对象元数据是一组描述对象的键值对。
对象名称在 bucket 中应该是唯一的;但是,不同的 bucket 可以具有相同名称的对象。对象的名称是云存储中的一段对象元数据。对象名称可以包含任何 Unicode 字符组合(UTF-8 编码),长度必须小于 1024 字节。
对象名称必须满足以下要求:
- 对象名称不得包含回车符或换行符
- 对象名称不能以众所周知的/acme 挑战开头
如果希望使对象名称看起来像存储在层次结构中一样,例如/team,则可以在对象名称中包含公共字符斜杠(/)。
要包含在对象名称中的常见字符是斜杠(/)。通过使用斜杠,可以使对象看起来像存储在层次结构中一样。例如,您可以将一个对象命名为/team/alpha/report1.jpg,另一个对象命名为object/team/alpha/report2.jpg。当您列出这些对象时,它们似乎处于基于团队的分层目录结构中;但是,对于云存储,对象是单个数据块,而不是层次结构。
除了名称之外,每个对象都有一个名为生成号的关联号。每当对象被覆盖时,其生成编号都会更改。云存储还支持一种称为对象版本控制的功能,该功能允许您引用被覆盖或删除的对象。一旦为 bucket 启用了对象版本控制,它将创建对象的存档版本,该版本将被覆盖或删除,并关联唯一的生成号以唯一标识对象。
谷歌云平台中的任何实体都是一种资源。无论它是一个项目、一个桶还是一个对象,在谷歌云平台上,它都是一种资源。
每个资源都有一个相关联的唯一名称来标识它。每个 bucket 都有一个资源名,格式为projects/_/buckets/【bucket\u name】,其中【bucket\u name】是 bucket 的 ID。每个对象都有一个资源名,格式为projects/_/buckets/【BUCKET\u name】/objects/【object\u name】,其中【object\u name】是对象的 ID。
也可以将#[NUMBER]追加到资源名称的末尾,以指示对象的特定生成;#0 是一个特殊标识符,用于表示对象的最新版本。当对象的名称以字符串结尾,否则将被解释为一个生成号时,#0 可能会很有用。
在云存储中,当上传对象时,您不能在其整个生命周期内对其进行更改。成功上载对象和成功删除对象之间的时间是对象的生存期。这本质上意味着您不能通过向现有对象追加一些数据或截断其中的一些数据来修改该对象。但是,您可以覆盖云存储中的对象。请注意,在成功上载文档的新版本之前,用户可以访问文档的旧版本。
A single particular object can only be updated or overwritten up to once per second.
现在,我们已经了解了云存储的基础知识,让我们来探索一下云存储中可用的存储类。
谷歌云存储支持基于不同用例的一系列存储类。其中包括用于频繁访问的数据的多区域和区域存储,用于不太频繁访问的数据(如每月使用不超过一次的数据)的近线存储,以及用于不经常访问的数据(如每年使用很少的数据)的冷线存储。
让我们一个接一个地看一遍。
多区域存储是一种地理冗余存储;它将您的数据存储在全球多个地理位置或数据中心。它将您的数据存储在存储桶的多区域位置内至少相隔 100 英里的两个地理位置。它是低延迟高可用性应用程序的理想选择,其中您的应用程序提供内容,如视频、音频或游戏内容的实时流式传输,由于数据冗余,它提供了高可用性。与其他存储类相比,它的成本稍高一些。
确保99.95%的可用性 SLA*。由于您的数据保存在多个位置,即使在发生自然灾害或任何其他中断的情况下,它也提供了高可用性。
存储为多区域存储的数据只能放在多区域位置,如美国、欧盟或亚洲,而不能放在特定区域位置,如美国中部 1 或亚洲东部 1。
区域存储将数据存储在特定的区域位置,而不是将冗余分布在不同的地理位置。与多区域存储相比更便宜,并确保了99.9%的可用性 SLA*。
区域存储更适合于将数据存储在使用该数据的服务器实例的同一区域位置。它提供了更好的性能,此外,还可以降低网络费用。
有可能在某个时间点,应用程序或企业在所有收集的数据中经常只使用部分数据。在这种情况下,多区域或区域存储将不是理想的选择,而且将是一个昂贵的选择。云存储提供了另一种称为“近线存储”的存储类,可以解决以前的问题。它是一种低成本的存储服务,用于存储访问频率较低的数据。在需要略微降低可用性的情况下,近线存储比多区域存储或区域存储更好。例如,您每月对整个月收集的数据进行一次分析。确保99.0%的可用性 SLA*。
近线存储还更适合于数据备份、灾难恢复和归档存储。但是,请注意,对于访问频率低于一年一次的数据,Coldline 存储是最具成本效益的选择,因为它提供了最低的存储成本。
Coldline storage 是一种非常低成本、高度耐用的存储服务,用于数据归档和灾难恢复。尽管它像一个“冷存储器”,但它提供了对数据的低延迟访问。它是您每年需要一到两次数据的最佳选择。您还可以将日常备份和归档文件存储到 Coldline,因为您不需要定期使用它们,而且只有在灾难恢复时才需要它们。它确保了99.0%的可用性 SLA*。
当用户在创建 bucket 时未指定默认存储类时,它将被视为标准存储对象。在这样的存储桶中没有存储类而创建的对象也被列为标准存储。如果铲斗位于多区域位置,则标准存储等同于多区域存储,当铲斗位于区域存储时,则视为位于区域存储。
请注意,定价也会相应进行。如果相当于多区域存储,则将收取多区域存储的费用。
现在我们了解了不同的存储类,让我们了解云存储中对象的生命周期管理。
许多应用程序需要在一定时间后删除或归档旧资源的功能。以下是一些示例用例:
- 将超过 1 年的文件从多区域存储移动到 Coldline 存储。
- 从 Coldline 存储中删除 5 年以上的文件。
- 如果有对象版本控制,则只保留几个最新的对象版本。
幸运的是,Google 云存储提供了一种称为对象生命周期管理的功能,可以根据配置自动处理此类操作。这些配置是一组适用于已启用此功能的 bucket 的规则。
例如,以下规则指定删除超过 365 天的文件:
// lifecycle.json
{
"lifecycle": {
"rule":
[
{
"action": {"type": "Delete"},
"condition": {"age": 365}
}
]
}
}Google Cloud Platform 为云存储提供 SDK,并为不同的平台提供许多其他产品,如 Node.js、Java、Python、Ruby、PHP 和 go。如果您不使用任何客户端库,它将提供 RESTAPI。它还提供了一个名为gsutil的命令行工具,允许您执行对象管理任务,包括以下内容:
- 上载、下载和删除对象
- 列出存储桶和对象
- 移动、复制和重命名对象
- 编辑对象和 bucket ACL
有许多选项可用于存储桶和对象的访问管理。让我们看一个总结:
- 身份和访问管理(IAM权限:为您的项目和存储桶提供广泛级别的控制。授予对 bucket 的访问权限并允许对 bucket 中的对象执行批量操作非常有用。
- 访问控制列表(ACL):为您提供细粒度控制,允许用户对单个 bucket 或对象进行读写访问。
- 签名 URL(查询字符串认证):通过签名 URL 在有限的时间段内授予对对象的读或写访问权限。
- S已签署的策略文档:允许您定义规则并对 bucket 中可以上传哪些对象进行验证,例如根据文件大小或内容类型进行限制。
- Firebase 安全规则:提供细粒度和基于属性的规则语言,提供使用 Firebase SDK 进行云存储的移动应用和 web 应用的访问。
现在我们已经熟悉了 Google 云存储的关键概念,让我们回到 Firebase 的云存储。
Firebase 云存储继承了 Google 云存储的优势或功能。但是,它还有一些附加功能,例如声明性安全规则语言,用于指定安全规则。
云存储的主要功能如下:
-
易用性和健壮性:Firebase 云存储是一个简单而强大的解决方案,用于存储和检索用户生成的内容,如文档、照片、音频或视频。它提供了强大的上载和下载功能,以便在 internet 连接中断时暂停文件传输,并在再次连接时从原来的位置恢复文件传输。它可以节省时间和互联网带宽。云存储的 API 也很简单,可以通过使用 Firebase SDK 来使用。
-
**强大的安全性:**说到云存储,我们首先考虑的是安全性。它足够安全吗?我的文件会怎么样?这些问题显而易见,也很重要。答案是肯定的,Firebase 的云存储非常安全。它拥有谷歌安全的力量。它与 Firebase 认证集成,为开发人员提供直观的认证。还可以使用声明性安全规则根据内容类型、名称或某些其他属性限制对文件的访问。
-
**高可扩展性:**Firebase 的云存储由谷歌基础设施支持,它提供了一个高度可扩展的存储环境,您可以轻松地将应用程序从原型扩展到产品。这个基础设施已经支持最流行和高流量的应用程序,如 Youtube、Google photos 和 Spotify。
-
**经济高效:**云存储是一种经济高效的解决方案,您只需为所用付费。您不需要购买和维护托管文件的服务器。
-
**与其他 Firebase 产品的集成良好:**云存储与其他 Firebase 产品的集成良好,例如,在我们的上一章中,我们已经看到云存储触发器可以触发云函数,这些云函数可以基于云存储上的文件操作执行一些逻辑。
我们已经了解了 Firebase 云存储的主要功能和优势。让我们看看它是如何工作的。
Firebase SDK for Cloud Storage 可用于直接从客户端上载和下载文件。客户端可以在其停止的位置重试以恢复操作,从而节省用户的时间和带宽。
在引擎盖下,云存储将您的文件存储在谷歌云存储桶中,因此可以通过 Firebase 和谷歌云访问这些文件。这使您能够灵活地通过 Firebase SDK 从移动客户端上传和下载文件,并进行服务器端处理,例如使用谷歌云平台生成图像缩略图或视频转码。正如我们所看到的,云存储可以自动扩展,它可以处理所有类型的应用程序数据,从小型到中型到大型应用程序。
在安全方面,Firebase SDK for Cloud Storage 与 Firebase 认证无缝集成以识别用户。正如我们在第 6 章、Firebase 安全和规则中看到的,Firebase 还提供声明性规则语言,允许您控制对单个文件或文件组的访问。
让我们增强我们的帮助台应用程序,用户可以上传他们的个人资料图片。
使用 Firebase SDK,我们可以轻松地在应用程序中集成和设置 Firebase 的云存储。
要设置云存储,您需要存储桶的 URL,您可以从我们的 Firebase 控制台获得该 URL。您可以从Storage菜单的Files选项卡中获取,如图所示:
一旦获得它,您就可以将其添加到 Firebase 配置中。
考虑这个例子:
import firebase from 'firebase';
const config = {
apiKey: "AIzaSyDO1VEnd5VmWd2OWQ9NQkkkkh-ehNXcoPTy-w",
authDomain: "demoproject-7cc0d.firebaseapp.com",
databaseURL: "https://demoproject-7cc0d.firebaseio.com",
projectId: "demoproject-7cc0d",
storageBucket: "gs://demoproject-7cc0d.appspot.com",
messagingSenderId: "41428255555"
};
export const firebaseApp = firebase.initializeApp(config);
// Get a reference to the storage service,
var storage = firebase.storage();现在我们已经准备好使用云存储。现在我们需要创建一个引用,该引用可用于在文件层次结构中导航。
我们可以通过调用ref()方法得到一个引用,如下所示:
var storage = firebase.storage();还可以创建对树中特定较低节点的引用。例如,要获得对images/homepage.png的引用,我们可以这样写:
var homepageRef = storageRef.child('images/homepage.jpg');您还可以导航到文件层次结构中的上级或下级:
// move to the parent of a reference - refers to images
var imagesRef = homepageRef.parent;
//move to highest parent or top of the bucket
var rootRef = homepageRef.root;
//chaining can be done for root, parent and child for multiple times
homepageRef.parent.child('test.jpg');有三个属性fullPath、name和bucket可供参考,以便更好地理解引用的文件:
// File path is 'images/homepage.jpg'
var path = homepageRef.fullPath
// File name is 'homepage.jpg'
var name = homepageRef.name
// Points to 'images'
var imagesRef = homepageRef.parent;现在,我们已经为上传功能做好了准备。我们将扩展我们的帮助台应用程序,并为用户提供上载屏幕截图以及票证其他详细信息的功能。我们将上传的图片存储在 Firebase 的云存储中,并仅从那里检索。
您可以上载文件或 Blob 类型、Uint8Array 或 base64 编码字符串,以将文件上载到云存储。在我们的示例中,我们将使用文件类型。如前所述,首先我们需要获取对文件完整路径的引用,包括文件名。
我们将修改AddTicketForm.jsx文件,允许用户上传与车票相关的屏幕截图或图像。
src/add-ticket/'AddTicketForm.jsx'文件现在如下所示。更改以粗体突出显示,并带有注释:
import React, { Component } from 'react';
import firebase from '../firebase/firebase-config';
import { ToastSuccess, ToastDanger } from 'react-toastr-basic';
class AddTicketForm extends Component {
constructor(props) {
super(props);
this.handleSubmitEvent = this.handleSubmitEvent.bind(this);
this.handleChange = this.handleChange.bind(this);
this.onChange = this.onChange.bind(this);
console.log(props.userInfo);
this.state = {
uId: props.userId,
email: props.userInfo[0].email,
issueType: "",
department: "",
comment: "",
snapshot: null
}
}
handleChange(event) {
console.log(event.target.value);
this.setState({
[event.target.id]: event.target.value
});
}
//handle onchange - set the snapshot value to the file selected
onChange(e) {
console.log("ff ",e.target.files[0] );
this.setState({snapshot:e.target.files[0]})
}
handleSubmitEvent(e) {
e.preventDefault();
var storageRef = firebase.storage().ref();
// Create a reference to 'image'
var snapshotRef = storageRef.child('ticket_snapshots/'+this.state.snapshot.name);
//get a reference to 'this' in a variable since in callback this will point to different object
var _this = this;
snapshotRef.put(this.state.snapshot).then(function(res) {
console.log('Uploaded a blob or file!');
console.log(res.metadata);
const userId = _this.state.uId;
var data = {
date: Date(),
email: _this.state.email,
issueType: _this.state.issueType,
department: _this.state.department,
comments: _this.state.comment,
status: "progress",
snapshotURL: res.metadata.downloadURLs[0] //save url in db to use it for download
}
console.log(data);
var newTicketKey = firebase.database().ref('/helpdesk').child('tickets').push().key;
// Write the new ticket data simultaneously in the tickets list and the user's ticket list.
var updates = {};
updates['/helpdesk/tickets/' + userId + '/' + newTicketKey] = data;
updates['/helpdesk/tickets/all/' + newTicketKey] = data;
return firebase.database().ref().update(updates).then(() => {
ToastSuccess("Saved Successfully!!");
this.setState({
issueType: "",
department: "",
comment: "",
snapshot: _this.state.snapshot
});
}).catch((error) => {
ToastDanger(error.message);
});
});
//React form data object
}
//render() method - snippet given below
}
export default AddTicketForm;让我们了解前面的代码:
- 在状态中添加快照属性。
OnChange()-为文件注册onChange()事件,将其设置在状态的快照字段中。onHandleSubmit()-我们创建了对该文件的引用,将其存储在 Firebase Cloud storage 中名为'ticket_snapshots'的文件夹中。一旦文件上传成功,我们将从响应元数据中获得一个下载 URL,该 URL 与其他票证详细信息一起存储在实时数据库中。
您还将在render()方法中进行一些 HTML 更改,以添加用于文件选择的输入字段:
render() {
var style = { color: "#ffaaaa" };
return (
<form onSubmit={this.handleSubmitEvent} >
<div className="form-group">
<label htmlFor="email">Email <span style={style}>*</span></label>
<input type="text" id="email" className="form-control"
placeholder="Enter email" value={this.state.email} disabled
required onChange={this.handleChange} />
</div>
<div className="form-group">
<label htmlFor="issueType">Issue Type <span style={style}> *</span></label>
<select className="form-control" value={this.state.issueType}
id="issueType" required onChange={this.handleChange}>
<option value="">Select</option>
<option value="Access Related Issue">Access Related
Issue</option>
<option value="Email Related Issues">Email Related
Issues</option>
<option value="Hardware Request">Hardware Request</option>
<option value="Health & Safety">Health & Safety</option>
<option value="Network">Network</option>
<option value="Intranet">Intranet</option>
<option value="Other">Other</option>
</select>
</div>
<div className="form-group">
<label htmlFor="department">Assign Department
<span style={style}> *</span></label>
<select className="form-control" value={this.state.department} id="department" required onChange={this.handleChange}>
<option value="">Select</option>
<option value="Admin">Admin</option>
<option value="HR">HR</option>
<option value="IT">IT</option>
<option value="Development">Development</option>
</select>
</div>
<div className="form-group">
<label htmlFor="comments">Comments <span style={style}> *</span></label>
(<span id="maxlength"> 200 </span> characters left)
<textarea className="form-control" rows="3" id="comment" value={this.state.comment} onChange={this.handleChange} required></textarea>
</div>
<div className="form-group">
<label htmlFor="fileUpload">Snapshot</label>
<input id="snapshot" type="file" onChange={this.onChange} />
</div>
<div className="btn-group">
<button type="submit" className="btn btn-
primary">Submit</button>
<button type="reset" className="btn btn-
default">cancel</button>
</div>
</form>
);
}我们的“添加票证”表单如下所示:
然后,您可以检查 Firebase 控制台,查看文件上载是否正常。以下截图显示我们上传的文件(helpdesk-db.png已成功保存在 Firebase 云存储中:
如前所述,Firebase 云存储与 Google 云存储高度集成,并使用一桶 Google 云存储来存储文件。您可以在登录您的谷歌云平台控制台 https://console.cloud.google.com/storage 并在储存区下方进行检查。你应该看到所有上传的文件也有。
下一个屏幕截图显示,可以从 Google 云平台控制台查看这些文件:
现在,您还可以检查数据库,查看已创建的票证是否具有快照 URL 属性和文件的相应值 downloadURL。
以下数据库屏幕截图显示快照 URL 已正确存储:
耶!云存储与我们的应用程序集成。然而,我们还没有完成。我们需要允许用户查看上传的图像,因此我们也将实现下载文件功能。但是,在我们开始下载文件功能之前,我想提一下,您应该更新云存储的安全规则,以控制对文件的访问。根据默认规则,需要 Firebase 认证才能对所有文件执行任何.read和.write操作。
默认规则如下图所示:
但是,您应该根据您的要求进行更新。
上载文件时,还可以存储该文件的一些元数据,例如内容类型或名称。
您可以使用 key:value 对创建 JSON 对象,并在上载文件时传递该对象。对于自定义元数据,可以在元数据对象内创建对象,如下所示:
// Create file metadata including the content type
var metadata = {
contentType: 'image/jpeg',
customMetadata: {
'ticketNo':'12345'
}
};
// Upload the file and metadata
var uploadTask = storageRef.child('folder/file.jpg').put(file, metadata);云存储允许您管理文件上传;您可以继续、暂停或取消上载。UploadTask上有相应的方法,通过put()或putString()方法返回,可以作为承诺或用于管理和监控上传状态:
// Upload the file and metadata
var uploadTask = storageRef.child('folder/file.jpg').put(file);
// Pause the upload - state changes to pause
uploadTask.pause();
// Resume the upload - state changes to running
uploadTask.resume();
// Cancel the upload - returns an error indicating file upload is cancelled
uploadTask.cancel();您可以使用“状态更改”观察者来收听进度事件。如果您想为文件上传显示一些实时进度条,这非常有用:
| 事件类型 | 用法 | | 跑步 | 当任务开始或恢复上载时,将触发此事件。 | | 进步 | 当任何数据上载到云存储时,将触发此事件。用于显示上传进度条。 | | 暂停 | 上载暂停时,将触发此事件。 |
当事件发生时,会传回一个TaskSnapshot对象,用于查看事件发生时的任务。
对象被传回。它包含以下属性:
| 所有物 | 类型 | 描述 |
| 传输的字节数 | Number | 拍摄快照时已传输的总字节数。 |
| 总字节 | Number | 要上载的总字节数。 |
| 状态 | firebase.storage.TaskState | 当前上载状态 |
| 元数据 | firebaseStorage.Metadata | 包含上传完成时服务器发送的元数据;在此之前,包含发送到服务器的元数据。 |
| 任务 | firebaseStorage.UploadTask | 可用于暂停、取消或恢复任务。 |
| 裁判 | firebaseStorage.Reference | 此任务来自的引用。 |
上载文件时,可能会发生错误。您可以使用回调中得到的错误对象来处理错误。
以下代码段显示了管理文件上载和错误处理的示例代码:
// File
var file = this.state.snapshot;
// Create the file metadata
var metadata = {
contentType: 'image/jpeg'
};
// Upload file and metadata to the object 'images/mountains.jpg'
var uploadTask = storageRef.child('ticket_snapshots/' + file.name).put(file, metadata);
// Listen for state changes, errors, and completion of the upload.
uploadTask.on(firebase.storage.TaskEvent.STATE_CHANGED, // or 'state_changed'
function(snapshot) {
// Get task progress, including the number of bytes uploaded and the total number of bytes to be uploaded
var progress = (snapshot.bytesTransferred / snapshot.totalBytes) * 100;
console.log('Upload is ' + progress + '% done');
switch (snapshot.state) {
case firebase.storage.TaskState.PAUSED: // or 'paused'
console.log('Upload is paused');
break;
case firebase.storage.TaskState.RUNNING: // or 'running'
console.log('Upload is running');
break;
}
}, function(error) {
// A full list of error codes is available at
// https://firebase.google.com/docs/storage/web/handle-errors
switch (error.code) {
case 'storage/unauthorized':
// User doesn't have permission to access the object
break;
case 'storage/canceled':
// User canceled the upload
break;
case 'storage/unknown':
// Unknown error occurred, inspect error.serverResponse
break;
}
}, function() {
// Upload completed successfully, now we can get the download URL
var downloadURL = uploadTask.snapshot.downloadURL;
});现在,让我们转到下载文件部分。
要下载文件,您需要使用文件的https:// or gs://URL 获取对该文件的引用,或者您可以通过将子路径附加到存储根目录来构造该文件。
下一个代码段显示了以下方法:
var storage = firebase.storage();
var pathReference = storage.ref('images/stars.jpg');
// Create a reference from a Google Cloud Storage URI
var gsReference = storage.refFromURL('gs://bucket/folder/file.jpg')
// Create a reference from an HTTPS URL
// Note that in the URL, characters are URL escaped!
var httpsReference = storage.refFromURL('https://firebasestorage..../file.jpg')我们将扩展我们的帮助台应用程序,允许用户查看票证的快照(如果有)。您需要更新ticket-listing文件夹下ViewTickets.jsx文件中的代码。我们已经从数据库中获取 URL,因此不需要获取引用即可获取下载 URL:
componentDidMount() {
const itemsRef = firebase.database().ref('/helpdesk/tickets/'+this.props.userId);
itemsRef.on('value', (snapshot) => {
let tickets = snapshot.val();
if(tickets != null){
let ticketKeys = Object.keys(tickets);
let newState = [];
for (let ticket in tickets) {
newState.push({
id:ticketKeys,
email:tickets[ticket].email,
issueType:tickets[ticket].issueType,
department:tickets[ticket].department,
comments:tickets[ticket].comments,
status:tickets[ticket].status,
date:tickets[ticket].date,
snapshotURL: tickets[ticket].snapshotURL
});
}
this.setState({
tickets: newState
});
}
});
}
render() {
return (
<table className="table">
<thead>
<tr>
<th>Email</th>
<th>Issue Type</th>
<th>Department</th>
<th>Comments</th>
<th>Status</th>
<th>Date</th>
<th>Snapshot</th>
</tr>
</thead>
<tbody>
{
this.state.tickets.length > 0 ?
this.state.tickets.map((item,index) => {
return (
<tr key={item.id[index]}>
<td>{item.email}</td>
<td>{item.issueType}</td>
<td>{item.department}</td>
<td>{item.comments}</td>
<td>{item.status === 'progress'?'In Progress':''}</td>
<td>{item.date}</td>
<th><a target="_blank" href={item.snapshotURL}>View</a></th>
</tr>
)
}) :
<tr>
<td colSpan="5" className="text-center">No tickets found.</td>
</tr>
}
</tbody>
</table>
);和文件上传一样,您也需要以类似的方式处理下载错误。
现在,让我们看看如何从云存储中删除文件。
要删除一个文件,首先需要获得该文件的引用,正如我们在 upload and download 中看到的一样。一旦你得到一个引用,你可以调用一个delete()方法来删除一个文件。它返回一个承诺,在成功的情况下解析,或者在错误的情况下拒绝。
考虑这个例子:
// Create a reference to the file to delete
var fileRef = storageRef.child('folder/file.jpg');
// Delete the file
desertRef.delete().then(function() {
// File deleted successfully
}).catch(function(error) {
// an error occurred!
});现在,让我们看看什么是谷歌应用程序引擎。
GoogleAppEngine 是一个“平台即服务”的平台,它消除了对基础设施的担忧,让您只关注代码。它提供了一个自动可扩展的平台,可根据接收的流量进行扩展。你只需要上传你的代码,它就会自动管理你的应用程序的可用性。Google App Engine 是一种简单快捷的方法,可以为 Firebase 应用程序添加额外的处理能力或可信的执行。
如果您有 App Engine 应用程序,则可以使用内置的 App Engine API 在 Firebase 和 App Engine 之间共享数据,因为 Firebase SDK for Cloud Storage 使用 Google App Engine 默认存储桶。这对于执行计算密集型背景处理或图像操作非常有用,例如创建上载图像的缩略图。
Google App Engine 标准环境提供了一个环境,您的应用程序可以在沙箱中运行,使用受支持语言的运行时环境,即 Python 2.7、Java 8、Java 7、PHP 5.5 和 Go 1.8、1.6。如果您的应用程序代码需要这些语言的其他版本或其他语言,您可以使用 Google App Engine 灵活环境,在该环境中,您的应用程序运行在 docker 容器上,docker 容器运行在 Google 云虚拟机上。
这两个环境之间有很多不同之处,可以在的谷歌云文档中找到 https://cloud.google.com/appengine/docs/the-appengine-environments 。
如果您想将现有的 Google 云平台项目导入 Firebase,并想使任何现有的 App Engine 对象可用,您需要在对象上设置默认访问控制,以允许 Firebase 通过使用gsutil运行以下命令来访问它们:
gsutil -m acl ch -r -u firebase-storage@system.gserviceaccount.com:O gs://<your-cloud-storage-bucket>Firebase 托管提供了一种在 CDN 上托管静态网站和资源的安全且简单的方法。托管的主要功能如下:
- 通过安全连接提供服务:内容始终通过 SSL 安全交付
- 更快的内容交付:文件缓存在全球 CDN 边缘,因此有更快的内容交付。
- 更快的部署:您可以在几秒钟内使用 Firebase CLI 部署应用程序
- 轻松快速的回滚:如果出现任何错误,只需一个命令即可回滚
托管为部署和管理静态网站提供了所有必要的基础设施、功能和工具,无论是单页应用程序还是复杂的渐进式应用程序。
默认情况下,您的站点将托管在firebaseapp.com域的子域上。使用 Firebase CLI,您可以将文件从计算机上的本地目录部署到主机服务器。
当您将站点移动到生产环境时,您可以将自己的域名连接到 Firebase 主机。
您需要安装 Firebase CLI 来部署静态 web 应用程序。
可以使用单个命令安装 Firebase CLI:
npm install -g firebase-tools现在,让我们在云上部署帮助台应用程序。我们有两个帮助台项目:react 应用程序(一个称为代码的项目)和服务器应用程序(一个称为节点的项目)。让我们首先在 Firebase 主机上托管或部署客户端 react 应用程序。
进入项目目录(代码)并运行以下命令以初始化配置:
firebase init如以下屏幕截图所示,它将询问您“您希望为此文件夹设置哪个 Firebase 功能?”并且您需要选择“托管”:
它将在项目的根目录中创建一个firebase.json文件。firebase.json的结构如下:
{
"database": {
"rules": "database.rules.json"
},
"hosting": {
"public": "build",
"ignore": [
"firebase.json",
"**/.*",
"**/node_modules/**"
],
"rewrites": [
{
"source": "**",
"destination": "/index.html"
}
]
}
}public 属性告诉 Firebase 哪个目录要上传到主机。该目录必须存在于项目目录中。
现在可以使用以下命令部署站点:
firebase deploy它将要求您进行 Firebase CLI 登录。可以使用以下命令执行此操作:
firebase login --reauth成功登录后,您可以再次运行firebase deploy命令来部署您的应用程序:
部署成功后,您将看到一个项目的托管 URL,类似于https://YOUR-FIREBASE-APP>.firebaseapp.com。在我们的例子中,它是*https://demoproject-7cc0d.firebaseapp.com/ .60.*现在您可以点击生成的 URL 并确认其可访问:
耶!我们已经在 Firebase 主机上部署了我们的第一个应用程序。您还可以在 Firebase 控制台的主机部分下检查 URL:
您也可以通过点击连接域按钮来配置您的自定义域。它将引导您通过向导来配置自己的域。
本章介绍了谷歌云平台。它让您基本了解了谷歌云存储和谷歌应用引擎,以及我们如何将 Firebase 云存储与谷歌云存储集成。我们探讨了 Firebase 的云存储,并了解了如何将文件上载、下载和删除到云存储。我们还扩展了 HelpDesk 应用程序,允许用户上传一个屏幕截图以及票证详细信息,还可以查看/下载上传的图像。此外,我们还探讨了如何在 Firebase 主机上部署我们的应用程序。
在下一章中,我们将讨论开发人员在使用 React 和 Firebase 时应遵循的编码标准和最佳实践,以获得更好的应用程序性能、减少错误数量,以及易于管理的应用程序代码。**









