Firebase Storage là một dịch vụ lưu trữ tệp đám mây thuộc hệ sinh thái Firebase của Google, được thiết kế để tải lên và tải xuống hình ảnh, video, âm thanh và dữ liệu nhị phân khác từ các ứng dụng di động và web. Không giống như ổ đĩa đám mây thông thường, Storage tích hợp với Firebase Authentication và Security Rules, cho phép kiểm soát truy cập linh hoạt đến từng tệp ở cấp độ yêu cầu. Theo Google Firebase (2026), dịch vụ này xử lý hơn 500 triệu thao tác tệp mỗi ngày, cung cấp lưu trữ có khả năng mở rộng mà không cần quản lý cơ sở hạ tầng máy chủ.
Những điểm chính
Firebase Storage là một kho lưu trữ đối tượng đám mây được xây dựng trên Google Cloud Storage, cung cấp SDK cho Android, iOS và các nền tảng web. Mỗi tệp được lưu trữ dưới dạng một đối tượng trong bucket Google Cloud và được định địa chỉ bằng đường dẫn giống hệ thống tệp: gs://bucket-name/path/to/file.jpg. Một tệp duy nhất có thể lên tới 5 TB, cho phép lưu trữ bất kỳ dữ liệu đa phương tiện nào mà không cần nén trước.
Kiến trúc của Firebase Storage sử dụng mô hình tham chiếu liên kết (gsutil references) thay vì phân cấp thư mục cổ điển, mặc dù SDK cung cấp giao diện thư mục để thuận tiện cho nhà phát triển. Về mặt vật lý, tất cả các đối tượng được lưu trữ trong không gian tên phẳng của bucket và các thư mục ảo được tạo bằng tiền tố đường dẫn. Điều này đảm bảo hiệu suất tìm kiếm tuyến tính bất kể số lượng tệp.
Lợi thế chính của Firebase Storage so với việc sử dụng trực tiếp Google Cloud Storage là tích hợp sẵn với Firebase Authentication và Security Rules. Nhà phát triển không cần cấu hình các vai trò IAM riêng biệt và tài khoản dịch vụ: các quy tắc truy cập được viết bằng ngôn ngữ khai báo tương tự Firebase Realtime Database Rules và được tự động áp dụng cho mọi yêu cầu.
Bucket Firebase Storage được tạo tự động khi bạn kích hoạt dịch vụ trong bảng điều khiển Firebase. Đường dẫn tệp tuân theo mẫu /tên_thư_mục/tên_tệp và có thể chứa các cấp độ lồng nhau. Nên tổ chức các đường dẫn theo sơ đồ /users/{userId}/images/{imageId}.jpg để cô lập dữ liệu giữa các người dùng. Cấu trúc này đơn giản hóa việc viết quy tắc bảo mật vì đường dẫn chứa định danh của chủ sở hữu.
Điều quan trọng là hiểu rằng Firebase Storage không phải là cơ sở dữ liệu quan hệ hay máy chủ tệp theo nghĩa cổ điển. Nó là kho lưu trữ đối tượng được tối ưu hóa cho các thao tác đọc và ghi toàn bộ tệp. Không thể cập nhật một phần tệp: nếu bạn tải lên lại cùng một đường dẫn, đối tượng cũ sẽ bị thay thế bằng đối tượng mới. Để lưu trữ dữ liệu có cấu trúc nhỏ, hãy sử dụng Firebase Realtime Database hoặc Cloud Firestore.
Giá cả của Firebase Storage phụ thuộc vào lượng dữ liệu được lưu trữ và số lượng thao tác. Gói miễn phí (Spark) bao gồm 5 GB bộ nhớ, 20.000 thao tác ghi và 50.000 thao tác đọc mỗi ngày. Gói trả phí (Blaze) tính phí dựa trên mức sử dụng thực tế: $0,026 mỗi GB dữ liệu được lưu trữ, $0,05 cho mỗi 10.000 thao tác ghi và $0,004 cho mỗi 10.000 thao tác đọc. Phí bổ sung áp dụng cho lưu lượng truy cập đi.
Đối với hầu hết ứng dụng di động với vài nghìn người dùng, giới hạn miễn phí là đủ trong giai đoạn tạo mẫu thử và thử nghiệm. Khi mở rộng quy mô lên hàng trăm nghìn người dùng, chi phí Storage hiếm khi vượt quá $50–$100 mỗi tháng với cách tiếp cận tải lên được tối ưu hóa và bộ nhớ đệm phía máy khách.
Tải tệp lên Firebase Storage được thực hiện thông qua phương thức SDK thích hợp, chấp nhận đường dẫn lưu trữ và dữ liệu tệp (mảng byte, URI, luồng hoặc Bitmap). SDK tự động quản lý kết nối, phân đoạn tệp thành các phần cho kích thước lớn và cung cấp callback để theo dõi tiến trình. Việc tải lên được thực hiện trực tiếp từ thiết bị khách đến Google Cloud, bỏ qua máy chủ của bạn, giảm tải cho cơ sở hạ tầng của riêng bạn.
Đối với Android, SDK Firebase Storage sử dụng các lớp StorageReference và UploadTask. StorageReference được tạo từ đường dẫn gốc qua Firebase.storage.reference và trỏ đến một tệp cụ thể trong bucket. UploadTask trả về các trình lắng nghe cho tiến trình, tạm dừng và hoàn thành. Khi kết nối bị gián đoạn, UploadTask tự động tiếp tục tải lên từ byte cuối cùng được truyền thành công — hành vi này được gọi là tải lên có thể tiếp tục.
Siêu dữ liệu tệp (Content-Type, trường tùy chỉnh) được truyền dưới dạng đối tượng SettableMetadata riêng biệt khi bắt đầu tải lên. Việc đặt chính xác Content-Type rất quan trọng để hiển thị tệp đúng cách trong trình duyệt và bộ nhớ đệm CDN. Firebase Storage hỗ trợ tất cả các loại MIME tiêu chuẩn: image/jpeg, image/png, video/mp4, application/pdf và các loại khác.
Siêu dữ liệu tệp chứa các trường hệ thống (Content-Type, Cache-Control, Content-Disposition) và các cặp khóa-giá trị tùy chỉnh (customMetadata). Các trường hệ thống kiểm soát tiêu đề HTTP khi tải xuống. Ví dụ: Cache-Control: public, max-age=31536000 kích hoạt bộ nhớ đệm phản hồi trong một năm, giảm đáng kể số lần tải xuống lặp lại của cùng một tệp và tiết kiệm lưu lượng truy cập.
Siêu dữ liệu tùy chỉnh thuận tiện để truyền thông tin bổ sung về tệp mà không cần tạo bộ sưu tập riêng trong Firestore. Ví dụ: trường uploadedBy có thể lưu trữ userId của người dùng đã tải lên, giúp đơn giản hóa việc triển khai thư viện với nội dung do người dùng tạo. Siêu dữ liệu tùy chỉnh không được Security Rules bảo vệ riêng — quyền truy cập của chúng được điều chỉnh bởi các quy tắc tương tự như chính tệp.
Khi bạn cần tải lên nhiều tệp cùng lúc (ví dụ: ảnh từ thư viện), không nên chạy các UploadTask độc lập song song mà không có giới hạn. Trên thiết bị di động, tải lên song song hơn 3–5 tệp sẽ làm quá tải ngăn xếp mạng và gây ra thời gian chờ. Chiến lược tối ưu là sử dụng giới hạn đồng thời là 3 hoặc tải lên tuần tự với thanh tiến trình chung.
Để xử lý phía máy chủ sau khi tải lên (tạo hình thu nhỏ, nén, kiểm duyệt nội dung), hãy sử dụng trình kích hoạt Firebase Cloud Functions: functions.storage.object().onFinalize(). Hàm này được gọi tự động sau khi mỗi tệp tải lên hoàn tất và có thể lưu bản sao đã xử lý vào một đường dẫn khác. Thông tin chi tiết hơn trong phần các trường hợp sử dụng điển hình.
Firebase Storage hỗ trợ hai phương pháp tải xuống: tải xuống trực tiếp qua SDK (lấy mảng byte hoặc tệp cục bộ) và lấy URL tải xuống trực tiếp để truy cập HTTP. URL trực tiếp có thể được sử dụng để hiển thị hình ảnh trong ImageView, trong WebView hoặc cung cấp liên kết cho người dùng. URL tải xuống được tạo với mã thông báo bảo mật có thể thu hồi trong bảng điều khiển Firebase.
Phương thức storageReference.downloadUrl trả về URL theo định dạng https://firebasestorage.googleapis.com/v0/b/{bucket}/o/{path}?alt=media&token={token}. Mã thông báo bảo mật tự động được bao gồm trong URL khi tạo, vì vậy liên kết có thể được chia sẻ với bên thứ ba (ví dụ: trong ứng dụng nhắn tin) mà không có rủi ro truy cập trái phép. Tuy nhiên, nếu mã thông báo bị xâm phạm, nó có thể bị thu hồi qua bảng điều khiển Firebase trong phần Storage — sau đó, tất cả các liên kết với mã thông báo này sẽ ngừng hoạt động.
Để lưu trữ đệm các tệp đã tải xuống trên máy khách, hãy sử dụng bộ nhớ cục bộ với cơ chế ETag hoặc băm MD5. Firebase Storage trả về tiêu đề HTTP ETag khi yêu cầu tệp, có thể được so sánh với giá trị được lưu trữ cục bộ để tránh tải xuống lại các tệp không thay đổi. Điều này đặc biệt hữu ích cho nội dung đa phương tiện: hình đại diện, ảnh bìa, bản xem trước — các tệp hiếm khi được cập nhật nhưng thường xuyên được yêu cầu.
URL tải xuống có mã thông báo là cách chính để cung cấp quyền truy cập tệp cho người dùng chưa xác thực (ví dụ: hiển thị hình ảnh trong bảng tin). Mã thông báo được tạo một lần và không thay đổi cho đến khi bị thu hồi, vì vậy URL có thể được lưu trữ trong cơ sở dữ liệu (ví dụ: bên cạnh trường avatarUrl trong Firestore). Khi hình đại diện được thay đổi, tệp cũ bị xóa và URL mới được tạo và lưu.
Điều quan trọng cần nhớ: có URL tải xuống không ghi đè Security Rules. Nếu quy tắc từ chối đọc tệp, phương thức downloadUrl sẽ trả về lỗi Từ chối quyền. Điều này có nghĩa là ngay cả khi biết đường dẫn tệp chính xác, máy khách chưa xác thực không thể lấy được liên kết. Sau khi có được, URL cung cấp quyền truy cập HTTP bỏ qua Security Rules — vì vậy mã thông báo là biện pháp bảo vệ duy nhất cho liên kết tải xuống.
HTTP ETag là định danh phiên bản tệp thay đổi mỗi khi nội dung được sửa đổi. Firebase Storage tự động trả về ETag trong phản hồi GET. Ứng dụng khách có thể lưu trữ ETag trong bộ nhớ đệm cục bộ và gửi tiêu đề If-None-Match: {etag} trong các yêu cầu tiếp theo. Nếu tệp không thay đổi, máy chủ trả về trạng thái 304 Không sửa đổi mà không truyền dữ liệu.
Để triển khai bộ nhớ đệm thông minh trong ứng dụng di động, hãy sử dụng kết hợp hệ thống tệp cục bộ và cơ sở dữ liệu (ví dụ: Room để lưu trữ các cặp đường dẫn-ETag). Khi tải tệp, hãy kiểm tra ETag từ cơ sở dữ liệu: nếu khớp với máy chủ, hãy sử dụng bản sao cục bộ. Cách tiếp cận này giảm lưu lượng truy cập 60–80% cho các tệp phương tiện tĩnh và tăng tốc độ tải màn hình có thư viện.
Security Rules là ngôn ngữ khai báo để kiểm soát truy cập vào các tệp trong Firebase Storage, được thực thi ở phía máy chủ Firebase. Mỗi quy tắc được gắn với một đường dẫn bucket và xác định các điều kiện mà theo đó thao tác đọc hoặc ghi được cho phép. Các quy tắc được kiểm tra trước mỗi yêu cầu và không thể bị bỏ qua bởi mã máy khách. Đây là tuyến phòng thủ duy nhất cho dữ liệu chống lại truy cập trái phép.
Quy tắc cơ bản là chỉ truy cập cho người dùng đã xác thực: allow read, write: if request.auth != null. Quy tắc này đảm bảo chỉ người dùng đã đăng nhập mới có thể đọc và ghi tệp. Để cấu hình chi tiết hơn, biến request.auth.uid được sử dụng, chứa định danh của người dùng hiện tại. Bằng cách so sánh uid với một phần của đường dẫn tệp, bạn có thể tạo bộ nhớ cách ly cho mỗi người dùng.
Quan trọng: Security Rules không phải là cơ chế xác thực nội dung. Nếu bạn cần kiểm tra loại tệp, kích thước hoặc sự hiện diện của mã độc, hãy sử dụng quy tắc request.resource, chứa siêu dữ liệu của tệp đã tải lên. Các thuộc tính có sẵn là request.resource.size (kích thước tệp), request.resource.contentType (loại MIME) và request.resource.md5Hash (tổng kiểm tra). Tuy nhiên, việc xác thực nội dung hoàn chỉnh được thực hiện ở phía máy chủ thông qua Cloud Functions.
| Tình huống | Quy tắc Security Rules |
|---|---|
| Chỉ xác thực | allow read, write: if request.auth != null |
| Chỉ chủ sở hữu | allow write: if request.auth.uid == userId |
| Đọc công khai | allow read: if true; allow write: if request.auth != null |
| Giới hạn kích thước | allow write: if request.resource.size < 5 * 1024 * 1024 |
| Giới hạn loại | allow write: if request.resource.contentType.startsWith('image/') |
Cấu hình điển hình cho ứng dụng có hình đại diện người dùng và thư viện như sau. Người dùng chỉ có thể ghi vào thư mục của riêng mình /users/{userId}/, nhưng có thể đọc bất kỳ tệp nào trong thư mục này (thư viện công khai). Kích thước tệp được giới hạn ở 5 MB và loại chỉ giới hạn ở hình ảnh. Sự kết hợp quy tắc này bao phủ 80% trường hợp sử dụng Firebase Storage trong các ứng dụng xã hội và UGC.
Mẹo bảo mật: không bao giờ sử dụng quy tắc allow read, write: if true cho toàn bộ bucket. Điều này mở quyền truy cập ghi cho bất kỳ ai biết projectId của bạn. Vào năm 2025, các cuộc tấn công vào các bucket Firebase không được bảo vệ đã gia tăng, khi kẻ tấn công sử dụng quyền truy cập mở để lưu trữ nội dung bất hợp pháp. Luôn bắt đầu với các quyền tối thiểu cần thiết và chỉ mở rộng chúng khi thực sự cần thiết.
Trình kích hoạt Cloud Functions functions.storage.object().onFinalize() cho phép thực hiện xác thực nội dung sau khi tải lên. Nếu tệp không vượt qua xác thực (ví dụ: chứa vi-rút hoặc vi phạm quy tắc nền tảng), hàm có thể xóa tệp và thông báo cho người dùng. Đây là cách duy nhất để kiểm tra nội dung thực tế vì Security Rules chỉ thấy siêu dữ liệu (kích thước và loại MIME), không phải dữ liệu nhị phân.
Ví dụ xác thực: hàm Node.js tải xuống tệp đã tải lên vào thư mục tạm thời, chạy nó qua trình phát hiện chống vi-rút (ví dụ: ClamAV) và nếu tìm thấy mối đe dọa — xóa tệp và ghi sự kiện vào Firebase Crashlytics. Thời gian thực thi hàm được giới hạn ở 540 giây, đủ để kiểm tra các tệp lên đến 50 MB.
Hãy xem các ví dụ thực tế về tích hợp Firebase Storage trong ứng dụng Android bằng Kotlin. Mã sử dụng các lớp SDK Firebase tiêu chuẩn và trình bày cách tải lên hình ảnh từ thư viện thiết bị, tải xuống tệp với theo dõi tiến trình và lấy URL tải xuống. Tất cả các ví dụ đều bao gồm xử lý lỗi và tạm dừng tác vụ khi mất kết nối.
Trước khi sử dụng mã, hãy đảm bảo tệp build.gradle bao gồm phụ thuộc implementation(platform("com.google.firebase:firebase-bom:33.0.0")) và implementation("com.google.firebase:firebase-storage"). Firebase BOM tự động chọn các phiên bản tương thích của tất cả SDK, loại bỏ xung đột phiên bản.
Ví dụ đầu tiên trình bày tải lên tệp do người dùng chọn qua Intent ACTION_GET_CONTENT. URI của tệp thu được được chuyển đến SDK Firebase Storage, SDK này đọc dữ liệu từ URI này. Phương thức putFile chấp nhận URI và trả về UploadTask — một đối tượng qua đó bạn có thể theo dõi tiến trình, tạm dừng và tiếp tục tải lên.
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", "Tệp đã được tải lên")
}
.addOnFailureListener { e ->
Log.e("Storage", "Lỗi: ${e.message}")
}
Trong ví dụ trên, biến storageRef là tham chiếu gốc đến bucket của dự án. Phương thức child chấp nhận một chuỗi đường dẫn và trả về StorageReference trỏ đến một tệp cụ thể. Nếu tệp tại đường dẫn đã chỉ định đã tồn tại, nó sẽ bị ghi đè. Siêu dữ liệu contentType và customMetadata được truyền qua đối tượng SettableMetadata, được đính kèm với yêu cầu putFile.
Ví dụ thứ hai trình bày tải xuống tệp bằng cách lấy mảng byte để hiển thị trong ImageView. Phương thức getBytes(maxSize) tải toàn bộ tệp vào bộ nhớ. Đối với tệp lớn hơn 10 MB, hãy sử dụng getFile(localUri) — nó lưu nội dung trực tiếp vào tệp cục bộ mà không lưu trữ trong RAM, ngăn ngừa OutOfMemoryError.
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", "Không thể tải lên: ${e.message}")
}
Để lấy URL tải xuống (ví dụ: để lưu liên kết trong Firestore), hãy sử dụng phương thức downloadUrl:
islandRef.downloadUrl.addOnSuccessListener { uri ->
Log.d("Storage", "URL tải xuống: $uri")
// Lưu uri.toString() vào Firestore
}
Mẹo: URL tải xuống được tạo một lần và ổn định cho đến khi bị thu hồi. Hãy lưu nó trong cơ sở dữ liệu ở lần tải lên đầu tiên thay vì yêu cầu mỗi khi bạn hiển thị tệp. Điều này giảm số lượng yêu cầu đến Firebase Storage và cải thiện hiệu suất giao diện người dùng.
Firebase Storage được sử dụng trong các ứng dụng di động để lưu trữ bất kỳ tệp người dùng và hệ thống nào. Các kịch bản phổ biến nhất bao gồm hình đại diện và ảnh hồ sơ, hình ảnh trong bảng tin nội dung, tệp video và âm thanh, tài liệu (PDF, DOCX) để chia sẻ giữa người dùng và sao lưu dữ liệu quy mô nhỏ. Trong tất cả các trường hợp này, Storage hoạt động như một kho lưu trữ tệp chuyên dụng kết hợp với Firestore để lưu trữ siêu dữ liệu và liên kết.
Ứng dụng xã hội là trường hợp sử dụng phổ biến nhất. Mỗi người dùng tải lên hình đại diện, ảnh bài đăng và tệp phương tiện. Cấu trúc đường dẫn /users/{uid}/posts/{postId}/image.jpg cô lập dữ liệu và đơn giản hóa Security Rules. Khi người dùng bị xóa, Cloud Function có thể duyệt qua tất cả các thư mục người dùng và dọn dẹp bộ nhớ. Theo blog Firebase (2025), mô hình này được sử dụng trong 70% dự án Firebase sản xuất.
Ứng dụng thương mại điện tử sử dụng Firebase Storage để lưu trữ ảnh sản phẩm, danh mục và tệp PDF có hướng dẫn. Trong trường hợp này, quyền truy cập tệp thường là công khai (đọc mà không cần xác thực), trong khi quyền ghi bị giới hạn cho quản trị viên thông qua Cloud Functions với kiểm tra quyền. URL tải xuống sản phẩm được lưu trữ trong Firestore cùng với dữ liệu sản phẩm khác, cho phép hiển thị hình ảnh mà không cần yêu cầu bổ sung đến Storage.
Ứng dụng nhắn tin và trò chuyện lưu trữ hình ảnh và tin nhắn thoại được gửi trong cuộc trò chuyện trong Firebase Storage. Đường dẫn được cấu trúc dưới dạng /chats/{chatId}/messages/{messageId}.jpg. Quyền truy cập đọc bị giới hạn cho những người tham gia trò chuyện, được xác minh thông qua Security Rules sử dụng dữ liệu Firestore. Đây là một trong số ít kịch bản mà quy tắc đọc dữ liệu từ dịch vụ Firebase khác: allow read: if firestore.exists(/databases/(default)/documents/chats/{chatId}/members/{request.auth.uid}).
Các câu hỏi thường gặp
Firebase Storage là lớp phủ trên Google Cloud Storage với tích hợp Firebase Authentication và Security Rules. Nhà phát triển không cần cấu hình vai trò IAM và tài khoản dịch vụ. Google Cloud Storage cung cấp các khả năng rộng hơn (thông báo Pub/Sub, Quản lý vòng đời đối tượng) nhưng yêu cầu quản lý truy cập thủ công qua GCP IAM.
Giới hạn kích thước được đặt trong Security Rules qua request.resource.size. Ví dụ: allow write: if request.resource.size <= 5 * 1024 * 1024 giới hạn tệp ở 5 MB. Ngoài ra, bạn có thể kiểm tra phía máy khách trước khi gửi để không lãng phí lưu lượng truy cập của người dùng vào các tệp rõ ràng không hợp lệ.
Có, việc xóa được thực hiện bằng phương thức delete() của đối tượng StorageReference: storageRef.child("path").delete(). Thao tác xóa không thể đảo ngược và xóa tệp khỏi bucket ngay lập tức. Tệp chỉ có thể bị xóa nếu Security Rules cho phép ghi cho đường dẫn đã cho. Sau khi xóa, URL tải xuống ngừng hoạt động.
Trong Security Rules, cho phép đọc cho tất cả (hoặc người dùng đã xác thực) và từ chối ghi: allow read: if request.auth != null; allow write: if false. Ghi trong chế độ này chỉ khả thi thông qua tài khoản dịch vụ Firebase Admin SDK — ví dụ: từ Cloud Functions với đặc quyền quản trị. Đây là mẫu tiêu chuẩn cho danh mục sản phẩm và nội dung công khai.
UploadTask sử dụng giao thức tải lên có thể tiếp tục dựa trên HTTP PUT với phân đoạn. Khi kết nối bị gián đoạn, quá trình tải lên tiếp tục từ byte đã xác nhận cuối cùng thay vì bắt đầu lại. Không cần cấu hình bổ sung cho hành vi này — SDK tự động thực hiện cho các tệp lớn hơn 1 MB.
Tổng kết
Chúng tôi sẽ phát triển ứng dụng di động chìa khóa trao tay
IT Sectr tạo các ứng dụng iOS và Android cho các công ty khởi nghiệp và doanh nghiệp từ năm 2017. Chúng tôi sẽ tư vấn và đề xuất giải pháp tốt nhất cho bạn.
Đọc thêm