Firebase Storage:是什么、文件上传与云端存储

作者: IT Sectr 发布日期: 2026-04-28 阅读时间: 14 分钟

Firebase Storage 是一项用于存储用户文件的云服务,属于 Google Firebase 生态系统的一部分,旨在从移动和 Web 应用程序上传和下载图像、视频、音频和其他二进制数据。与普通云盘不同,Storage 与 Firebase Authentication 和 Security Rules 集成,允许在请求级别灵活限制对每个文件的访问。根据 Google Firebase (2026) 的数据,该服务每天处理超过 5 亿次文件操作,提供可扩展存储,无需管理服务器基础设施。

要点

  • Firebase Storage — 用于应用程序文件的云存储,集成到 Firebase 平台中。
  • 上传通过 SDK 直接从客户端执行,绕过您自己的服务器。
  • 安全规则允许根据身份验证和内容控制对每个文件的访问。
  • 抗连接中断通过从中断点自动恢复来保证。
  • 与 Cloud Functions 集成允许在上传后处理文件。

什么是 Firebase Storage 及其结构

Firebase Storage 是一个基于 Google Cloud Storage 构建的云对象存储,为 Android、iOS 和 Web 平台提供 SDK。每个文件作为对象存储在 Google Cloud 存储桶中,通过类似文件系统的路径进行寻址:gs://bucket-name/path/to/file.jpg。单个文件的大小可达 5 TB,允许无需预先压缩即可存储任何媒体数据。

Firebase Storage 的架构使用链接引用模型(gsutil references),而非经典的文件夹层次结构,尽管 SDK 为了方便开发人员提供了带有目录的界面。实际上,所有对象都存储在存储桶的扁平命名空间中,虚拟文件夹通过路径前缀创建。这确保了无论文件数量多少,都能提供线性搜索性能。

Firebase Storage 相对于直接使用Google Cloud Storage的主要优势在于与 Firebase Authentication 和 Security Rules 的内置集成。开发人员无需设置单独的 IAM 角色和服务帐户:访问规则使用类似于 Firebase Realtime Database Rules 的声明性语言编写,并在每次请求时自动应用。

存储桶结构和文件路径

Firebase Storage 存储桶在 Firebase 控制台中激活服务时自动创建。文件的路径按照/文件夹名称/文件名称的原则构建,可以包含嵌套级别。建议按照/users/{userId}/images/{imageId}.jpg的方案组织路径,以便在用户之间隔离数据。这种结构简化了安全规则的编写,因为路径包含所有者标识。

重要的是要理解,Firebase Storage 不是传统意义上的关系数据库或文件服务器。它是一个针对完整文件读写操作优化的对象存储。无法更新文件的一部分:使用相同路径重新上传时,旧对象将被新对象替换。对于存储小型结构化数据,请使用 Firebase Realtime Database 或 Cloud Firestore。

Firebase Storage 的价格和限制

Firebase Storage 的价格取决于存储数据量和操作次数。免费套餐(Spark)包括 5 GB 存储空间、每天 20,000 次写入操作和 50,000 次读取操作。付费套餐(Blaze)按实际使用付费:每 GB 存储数据 $0.026,每 10,000 次写入操作 $0.05,每 10,000 次读取操作 $0.004。此外还需支付出站流量费用。

对于拥有几千用户的多数移动应用程序,免费限制在原型设计和测试阶段已足够。当扩展到数十万用户时,采用优化的上传和客户端缓存方法,Storage 成本很少超过每月 $50–$100。

如何上传文件到 Firebase Storage

上传文件到 Firebase Storage通过相应的 SDK 方法执行,该方法接受存储路径和文件数据(字节数组、URI、流或 Bitmap)。SDK 自动管理连接,对大文件进行分段,并提供回调以跟踪进度。上传直接从客户端设备到 Google Cloud,绕过您的服务器,减少您自己基础设施的负载。

对于 Android,Firebase Storage SDK使用 StorageReferenceUploadTask 类。StorageReference 通过 Firebase.storage.reference 从根路径创建,指向存储桶中的特定文件。UploadTask 返回进度、暂停和完成的监听器。当连接中断时,UploadTask 自动从最后成功传输的字节继续上传——这种行为称为可恢复上传(resumable upload)

文件元数据(Content-Type、自定义字段)在启动上传时通过单独的 SettableMetadata 对象传输。正确设置Content-Type对于文件在浏览器中的正确显示和 CDN 缓存的工作至关重要。Firebase Storage 支持所有标准 MIME 类型:image/jpeg、image/png、video/mp4、application/pdf 等。

上传时管理元数据

文件元数据包含系统字段(Content-Type、Cache-Control、Content-Disposition)和自定义键值对(customMetadata)。系统字段在下载时管理 HTTP 标头。例如,Cache-Control: public, max-age=31536000 启用响应缓存一年,显著减少相同文件的重复下载次数并节省流量。

自定义元数据便于在不创建 Firestore 单独集合的情况下传输有关文件的附加信息。例如,在 uploadedBy 字段中可以保存上传文件的用户的 userId,从而简化具有作者内容的画廊的实现。自定义元数据不由 Security Rules 单独保护——对它们的访问与文件本身受相同规则约束。

多文件上传和批处理

当需要同时上传多个文件时(例如,来自画廊的照片),不建议无限制地并行运行独立的 UploadTask。在移动设备上,超过 3-5 个文件的并行上传会导致网络堆栈超载和超时。最佳策略是使用并发限制 3 或顺序上传并显示总体进度条。

对于上传后的服务器端处理(生成缩略图、压缩、内容审核),使用 Firebase Cloud Functions 触发器:functions.storage.object().onFinalize()。此函数在每个文件上传完成后自动调用,并可以将处理后的副本保存到其他路径。更多信息请参见典型使用场景部分。

下载文件和管理链接

Firebase Storage支持两种下载方式:通过 SDK 直接下载(获取字节数组或本地文件),以及获取直接下载 URL 以通过 HTTP 访问。直接 URL 可用于在 ImageView、WebView 中显示图像,或向用户提供链接。下载 URL 使用安全令牌生成,可在 Firebase 控制台中撤销。

storageReference.downloadUrl 方法返回格式为 https://firebasestorage.googleapis.com/v0/b/{bucket}/o/{path}?alt=media&token={token} 的 URL。安全令牌在生成时自动包含在 URL 中,因此链接可以安全地共享给第三方(例如,在即时通讯工具中),而无需担心未经授权的访问。但是,如果令牌泄露,可以通过 Firebase 控制台的 Storage 部分撤销——之后所有包含此令牌的链接将停止工作。

对于客户端的已下载文件缓存,使用本地存储和 ETag 或 MD5 哈希机制。Firebase Storage 在请求文件时返回 HTTP ETag 标头,可以将其与本地存储的值进行比较,以避免重复下载未更改的文件。这对于媒体内容特别有用:头像、封面、预览——这些文件很少更新但经常被请求。

直接下载 URL 及其安全性

带令牌的下载 URL是向未经身份验证的用户提供文件访问的主要方式(例如,在新闻推送中显示图像)。令牌生成一次,在撤销前不会更改,因此 URL 可以保存在数据库中(例如,在 Firestore 中的 avatarUrl 字段旁边)。更换头像时,旧文件被删除,新 URL 生成并保存。

务必记住:下载 URL 的存在不会使 Security Rules 失效。如果规则禁止读取文件,downloadUrl 方法将返回 Permission Denied 错误。这意味着即使知道文件的正确路径,未经身份验证的客户端也无法获取链接。获取 URL 后,通过 HTTP 访问文件,绕过 Security Rules——因此令牌是下载链接的唯一保护。

缓存和 ETag 的使用

HTTP ETag是文件版本的标识符,每次内容更改时都会变化。Firebase Storage 在 GET 请求的响应中自动返回 ETag。客户端应用程序可以将 ETag 保存在本地缓存中,并在重复请求时发送 If-None-Match: {etag} 标头。如果文件未更改,服务器将返回 304 Not Modified 状态,而不传输数据。

要在移动应用程序中实现智能缓存,请使用本地文件系统和数据库的组合(例如,Room 用于存储路径-ETag 对)。下载文件时,从数据库检查 ETag:如果与服务器值匹配,则使用本地副本。这种方法可将静态媒体文件的流量减少 60-80%,并加速带画廊的屏幕加载。

Firebase Storage 的安全规则

Security Rules是一种声明性语言,用于限制对 Firebase Storage 中文件的访问,在 Firebase 服务器端执行。每个规则绑定到存储桶中的路径,并确定允许读取(read)或写入(write)操作的条件。规则在每次请求前进行检查,且无法被客户端代码绕过。这是防止未授权访问数据的唯一防线。

基本规则——仅允许经过身份验证的用户访问allow read, write: if request.auth != null。这样的规则确保只有登录用户才能读取和写入文件。对于更精细的设置,使用变量 request.auth.uid,其中包含当前用户的标识。通过将 uid 与文件路径的一部分进行比较,可以为每个用户创建隔离的存储空间。

重要提示:Security Rules 不是内容验证机制。如果需要检查文件类型、大小或恶意代码的存在,请使用 request.resource 规则,其中包含正在上传的文件的元数据。可用的属性包括 request.resource.size(文件大小)、request.resource.contentType(MIME 类型)和 request.resource.md5Hash(校验和)。然而,完整的内容检查通过 Cloud Functions 在服务器端执行。

场景Security Rules 规则
仅限经过身份验证的用户allow read, write: if request.auth != null
仅限所有者allow write: if request.auth.uid == userId
公开读取allow read: if true; allow write: if request.auth != null
大小限制allow write: if request.resource.size < 5 * 1024 * 1024
类型限制allow write: if request.resource.contentType.startsWith('image/')

用户内容规则示例

典型配置对于具有用户头像和画廊的应用程序如下所示。用户只能写入自己的目录 /users/{userId}/,但可以读取该目录中的任何文件(画廊是公开的)。文件大小限制为 5 MB,类型仅限于图像。这种规则组合覆盖了 Firebase Storage 在社交和 UGC 应用程序中 80% 的使用场景。

安全建议:切勿对整个存储桶使用 allow read, write: if true 规则。这会向任何知道您 projectId 的人开放写入权限。2025 年,针对未受保护的 Firebase 存储桶的攻击有所增加,攻击者利用开放访问权限存储非法内容。始终从最低必要权限开始,仅在明确需要时扩展。

通过 Cloud Functions 验证内容

Cloud Functions 触发器 functions.storage.object().onFinalize() 允许在上传后验证内容。如果文件未通过验证(例如,包含病毒或违反平台规则),该函数可以删除它并通知用户。这是检查实际内容的唯一方法,因为 Security Rules 只能看到元数据(大小和 MIME 类型),而不能看到二进制数据。

验证示例:Node.js 中的函数将上传的文件下载到临时目录,通过防病毒检测器(例如 ClamAV)运行,如果发现威胁——删除文件并将事件写入 Firebase Crashlytics。函数的执行时间限制为 540 秒,足以检查大小达 50 MB 的文件。

Kotlin 中 Firebase Storage 的代码示例

我们来看一下在 Kotlin 中将 Firebase Storage 集成到 Android 应用程序中的实际示例。代码使用 Firebase SDK 的标准类,演示了从设备图库上传图像、通过跟踪进度下载文件以及获取下载 URL。所有示例都包含错误处理和连接丢失时的任务暂停。

在使用代码之前,请确保在 build.gradle 文件中添加了依赖项 implementation(platform("com.google.firebase:firebase-bom:33.0.0"))implementation("com.google.firebase:firebase-storage")。Firebase BOM 会自动选择所有 SDK 的兼容版本,从而排除版本冲突。

从图库上传图像

第一个示例——上传文件,用户通过 Intent ACTION_GET_CONTENT 选择。获取的文件的 URI 传递给 Firebase Storage SDK,它独立地从该 URI 读取数据。putFile 方法接受 URI 并返回 UploadTask——一个可以通过它跟踪进度、暂停和恢复上传的对象。

kotlin
val storageRef = Firebase.storage.reference
val imageRef = storageRef.child(
    "users/${auth.uid}/profile.jpg"
)

val metadata = SettableMetadata().apply {
    contentType = "image/jpeg"
    customMetadata = mapOf(
        "uploadedBy" to auth.uid!!
    )
}

imageRef.putFile(imageUri, metadata)
    .addOnSuccessListener {
        Log.d("Storage", "文件已上传")
    }
    .addOnFailureListener { e ->
        Log.e("Storage", "错误:${e.message}")
    }

在上面的示例中,变量 storageRef 是项目存储桶的根引用。child 方法接受路径字符串并返回指向特定文件的 StorageReference。如果指定路径上的文件已存在,它将被覆盖。contentType 和 customMetadata 元数据通过附加到 putFile 请求的 SettableMetadata 对象传输。

带进度下载文件

第二个示例演示了下载文件并获取字节数组以在 ImageView 中显示。getBytes() 方法将整个文件加载到内存中。对于大于 10 MB 的文件,请使用 getFile()——它直接将内容保存到本地文件,无需存储在 RAM 中,从而防止 OutOfMemoryError。

kotlin
val islandRef = storageRef.child("images/island.jpg")

val ONE_MEGABYTE: Long = 1024 * 1024
islandRef.getBytes(ONE_MEGABYTE)
    .addOnSuccessListener { bytes ->
        imageView.setImageBitmap(
            BitmapFactory.decodeByteArray(
                bytes, 0, bytes.size
            )
        )
    }
    .addOnFailureListener { e ->
        Log.e("Storage", "上传失败:${e.message}")
    }

获取下载 URL(例如,将链接保存到 Firestore),请使用 downloadUrl 方法:

kotlin
islandRef.downloadUrl.addOnSuccessListener { uri ->
    Log.d("Storage", "下载 URL:$uri")
    // 将 uri.toString() 保存到 Firestore
}

提示:downloadUrl 生成一次,在撤销前保持稳定。在首次上传时将其保存在数据库中,不要在每次显示文件时都请求它。这减少了对 Firebase Storage 的请求次数,并加速了 UI 的运行。

Firebase Storage 的典型使用场景

Firebase Storage用于移动应用程序中存储所有用户和系统文件。最常见的场景是头像和个人资料照片、内容推送中的图像、视频和音频文件、用户之间交换的文档(PDF、DOCX),以及少量数据的备份。在所有这些情况下,Storage 作为专门的文件存储,与 Firestore 配合使用以存储元数据和链接。

社交应用程序——最常见的情况。每个用户上传头像、帖子照片和媒体文件。路径结构 /users/{uid}/posts/{postId}/image.jpg 允许数据隔离并简化 Security Rules。删除用户时,Cloud Function 可以遍历用户的所有目录并清理存储。根据 Firebase 博客(2025),此模式用于 Firebase 上 70% 的生产项目。

电子商务应用程序使用 Firebase Storage 存储产品照片、目录和带说明的 PDF 文件。在这种情况下,对文件的访问通常是公开的(无需身份验证即可读取),而写入仅限管理员通过 Cloud Functions 进行权限检查。产品的下载 URL 保存在 Firestore 中,位于其他产品数据旁边,允许无需额外请求 Storage 即可显示图像。

即时通讯和聊天在 Firebase Storage 中存储对话中发送的图像和语音消息。路径构建为 /chats/{chatId}/messages/{messageId}.jpg。读取访问权限——仅限聊天参与者,通过使用 Firestore 数据的 Security Rules 进行检查。这是规则从其他 Firebase 服务读取数据的少数场景之一:allow read: if firestore.exists(/databases/(default)/documents/chats/{chatId}/members/{request.auth.uid})

常见问题

Firebase Storage 与 Google Cloud Storage 有何不同?

Firebase Storage是 Google Cloud Storage 之上的附加层,集成了 Firebase Authentication 和 Security Rules。开发人员无需设置 IAM 角色和服务帐户。Google Cloud Storage 提供更广泛的功能(Pub/Sub 通知、Object Lifecycle Management),但需要通过 GCP IAM 进行手动访问管理。

如何限制上传文件的大小?

大小限制在Security Rules中通过 request.resource.size 设置。示例:allow write: if request.resource.size <= 5 * 1024 * 1024 将文件限制为 5 MB。此外,您可以在发送前在客户端进行检查,以避免在明显不允许的文件上浪费用户流量。

可以通过 Firebase Storage SDK 删除文件吗?

是的,删除使用 StorageReference 对象的 delete() 方法:storageRef.child("path").delete()。删除操作不可逆,会立即从存储桶中删除文件。仅当 Security Rules 允许对相应路径进行写操作时才能删除文件。删除后,下载 URL 将停止工作。

如何将存储设置为只读?

Security Rules中,允许所有人(或经过身份验证的用户)读取并禁止写入:allow read: if request.auth != null; allow write: if false。在此模式下,只能通过 Firebase Admin SDK 的服务帐户进行写入——例如,从具有管理权限的 Cloud Functions。这是产品目录和公共内容的标准模式。

Firebase Storage 如何处理上传时的连接中断?

UploadTask使用基于 HTTP PUT 和分段的可恢复上传协议。中断时,上传从最后一个已确认的字节继续,而不是重新开始。无需额外配置即可启用此行为——SDK 在文件大于 1 MB 时自动执行此操作。

总结

  • Firebase Storage — 基于 Google Cloud Storage 的云对象存储,集成了 Firebase Authentication 和 Security Rules。
  • 文件上传通过 SDK 直接从客户端执行,支持在连接中断时进行可恢复上传。
  • 下载可通过 SDK(字节数组或本地文件)或通过带安全令牌的直接下载 URL 进行。
  • Security Rules — 唯一的数据保护机制,允许根据路径、身份验证、大小和文件类型进行访问控制。
  • 通过 HTTP ETag 缓存在客户端正确实现的情况下,可将静态媒体文件的流量减少 60-80%。
  • Cloud Functions onFinalize 触发器允许文件后处理:压缩、审核、生成预览。
  • 定价可预测:5 GB 免费限额涵盖原型,付费 Blaze 套餐按实际使用计费。

我们将开发一款交钥匙移动应用程序

IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。

讨论项目

另请阅读