Hướng Dẫn Toàn Diện Cách Sử Dụng Firebase API (2026)

Ashley Innocent

Ashley Innocent

23 tháng 3 2026

Hướng Dẫn Toàn Diện Cách Sử Dụng Firebase API (2026)

Apidog cho doanh nghiệp

Triển khai tại chỗ

SSO & RBAC

Tuân thủ SOC 2

Khám phá Apidog Enterprise

Bạn đang xây dựng một ứng dụng. Người dùng cần đăng nhập. Dữ liệu cần đồng bộ hóa theo thời gian thực. Các tệp cần được lưu trữ. Bạn có thể thiết lập máy chủ, cấu hình cơ sở dữ liệu và quản lý hạ tầng trong nhiều tuần. Hoặc bạn có thể sử dụng Firebase.

Firebase cung cấp sức mạnh cho hơn 1,5 triệu ứng dụng bao gồm The New York Times, Duolingo và Alibaba. Các nhà phát triển chọn nó vì nó loại bỏ sự phức tạp của phần phụ trợ (backend). Bạn tập trung vào các tính năng, không phải bảo trì máy chủ. Nhưng API Firebase có những điểm khác biệt. Luồng xác thực làm người mới bối rối. Quy tắc cơ sở dữ liệu làm các nhà phát triển có kinh nghiệm gặp khó khăn. Cloud Functions có vẻ kỳ diệu cho đến khi bạn hiểu các kích hoạt của chúng.

Tôi đã tích hợp Firebase vào các ứng dụng sản xuất phục vụ hàng triệu người dùng. Tôi đã mắc mọi lỗi có thể: làm lộ khóa tài khoản dịch vụ, viết các truy vấn kém hiệu quả, triển khai các hàm bị lỗi. Hướng dẫn này chắt lọc những bài học đó.

Bạn sẽ học về xác thực, các thao tác cơ sở dữ liệu, Cloud Functions và lưu trữ. Bạn sẽ thấy mã hoạt động thực tế, không chỉ lý thuyết. Bạn sẽ tránh được những cạm bẫy gây ra các vấn đề nghiêm trọng trong sản xuất.

💡
Kiểm thử API Firebase trở nên dễ dàng hơn với các công cụ client API phù hợp. Apidog cho phép bạn tổ chức các điểm cuối, kiểm thử luồng xác thực và chia sẻ các bộ sưu tập với nhóm của bạn. Chúng tôi sẽ chỉ ra vị trí phù hợp tự nhiên của nó trong quy trình làm việc.

nút

API Firebase là gì và tại sao nó lại quan trọng?

Firebase không phải là một API duy nhất. Đó là một bộ các dịch vụ backend được truy cập thông qua các SDK hợp nhất và các điểm cuối REST.

Các Dịch vụ Firebase Cốt lõi

Dịch vụ Mục đích Loại API
Xác thực Đăng nhập người dùng và định danh SDK + REST
Cơ sở dữ liệu Firestore Cơ sở dữ liệu tài liệu NoSQL SDK + REST
Cơ sở dữ liệu Thời gian thực Đồng bộ hóa JSON thời gian thực SDK + REST
Cloud Storage Lưu trữ tệp và CDN SDK + REST
Cloud Functions Tính toán phi máy chủ (Serverless compute) CLI triển khai
Hosting Lưu trữ web tĩnh CLI triển khai
Cloud Messaging Thông báo đẩy API HTTP v1

Khi nào nên sử dụng Firebase

Firebase giải quyết tốt các vấn đề cụ thể:

Sử dụng Firebase khi:

Không sử dụng Firebase khi:

Kiến trúc API Firebase

Firebase sử dụng một cách tiếp cận lai:

┌─────────────────────────────────────────────────────────┐
│                    Ứng dụng của bạn                       │
├─────────────────────────────────────────────────────────┤
│  Firebase SDK (Client)                                   │
│  - Tự động xử lý mã thông báo xác thực                    │
│  - Quản lý bộ nhớ đệm ngoại tuyến                          │
│  - Trình lắng nghe thời gian thực                          │
└─────────────────────────────────────────────────────────┘
                          │
                          │ HTTPS + WebSocket
                          ▼
┌─────────────────────────────────────────────────────────┐
│                   Backend Firebase                       │
├──────────────┬──────────────┬──────────────┬────────────┤
│   Dịch vụ    │  Cơ sở dữ liệu │   Dịch vụ    │ Hàm        │
│   Xác thực  │  Firestore   │   Lưu trữ    │  Thời gian chạy │
└──────────────┴──────────────┴──────────────┴────────────┘

Các SDK client trừu tượng hóa lớp HTTP. Về bản chất, mọi thao tác đều được dịch thành các lệnh gọi API REST với xác thực JWT.

Xác thực Firebase: Thiết lập Hoàn chỉnh

Xác thực là tích hợp Firebase đầu tiên của bạn. Nếu làm sai bước này, mọi thứ khác sẽ thất bại.

Bước 1: Tạo dự án Firebase

  1. Truy cập Firebase Console
Giao diện Firebase Console hiển thị nút 'Thêm dự án'.

Nhấp vào "Thêm dự án" và Nhập tên dự án (không có khoảng trắng)

Giao diện Firebase Console để nhập tên dự án.

Bật Google Analytics (tùy chọn nhưng được khuyến nghị)

Giao diện Firebase Console để bật Google Analytics.

Nhấp vào "Tạo dự án"

Giao diện Firebase Console hiển thị thông báo tạo dự án.

Chờ 30 giây để hoàn tất việc cung cấp. Bạn sẽ thấy bảng điều khiển dự án.

Bước 2: Đăng ký ứng dụng của bạn

Đối với ứng dụng Web:

// Trong Firebase Console > Cài đặt dự án > Tổng quan
// Nhấp vào "Thêm ứng dụng" > biểu tượng Web

// Đăng ký ứng dụng web
const firebaseConfig = {
  apiKey: "AIzaSyDxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
  authDomain: "your-app.firebaseapp.com",
  projectId: "your-app",
  storageBucket: "your-app.appspot.com",
  messagingSenderId: "123456789012",
  appId: "1:123456789012:web:abc123def456"
};

// Khởi tạo Firebase
import { initializeApp } from 'firebase/app';
const app = initializeApp(firebaseConfig);

Đối với ứng dụng iOS:

Tải xuống GoogleService-Info.plist và thêm vào dự án Xcode. Đảm bảo "Target Membership" bao gồm ứng dụng của bạn.

Đối với ứng dụng Android:

Tải xuống google-services.json và đặt vào thư mục app/. Thêm vào build.gradle:

// build.gradle cấp dự án
buildscript {
    dependencies {
        classpath 'com.google.gms:google-services:4.4.0'
    }
}

// build.gradle cấp ứng dụng
plugins {
    id 'com.google.gms.google-services'
}

Bước 3: Bật các phương thức xác thực

Trong Firebase Console > Xác thực > Phương thức đăng nhập:

  1. Email/Mật khẩu: Bật để đăng ký truyền thống
  2. Google: Thêm dấu vân tay chứng chỉ SHA-1 của bạn (Android) hoặc ID gói (iOS)
  3. Apple: Bắt buộc đối với ứng dụng iOS nếu bạn bật bất kỳ đăng nhập xã hội nào
  4. Điện thoại: Bật để xác thực bằng SMS (yêu cầu thanh toán)

Bước 4: Triển khai luồng xác thực

Đăng ký bằng Email/Mật khẩu:

import {
  createUserWithEmailAndPassword,
  getAuth,
  updateProfile
} from 'firebase/auth';

const auth = getAuth(app);

async function signUp(email, password, displayName) {
  try {
    const userCredential = await createUserWithEmailAndPassword(
      auth,
      email,
      password
    );

    // Đặt tên hiển thị
    await updateProfile(userCredential.user, {
      displayName: displayName
    });

    console.log('Người dùng được tạo:', userCredential.user.uid);
    return userCredential.user;
  } catch (error) {
    // Xử lý các mã lỗi cụ thể
    switch (error.code) {
      case 'auth/email-already-in-use':
        throw new Error('Email này đã được sử dụng');
      case 'auth/weak-password':
        throw new Error('Mật khẩu phải có ít nhất 6 ký tự');
      case 'auth/invalid-email':
        throw new Error('Địa chỉ email không hợp lệ');
      default:
        throw new Error('Đăng ký thất bại: ' + error.message);
    }
  }
}

Đăng nhập bằng Email/Mật khẩu:

import {
  signInWithEmailAndPassword,
  signOut
} from 'firebase/auth';

async function signIn(email, password) {
  try {
    const userCredential = await signInWithEmailAndPassword(
      auth,
      email,
      password
    );

    const user = userCredential.user;

    // Lấy mã thông báo ID cho các lệnh gọi API
    const idToken = await user.getIdToken();
    console.log('Mã thông báo xác thực:', idToken);

    return user;
  } catch (error) {
    switch (error.code) {
      case 'auth/user-not-found':
        throw new Error('Không có tài khoản nào với email này');
      case 'auth/wrong-password':
        throw new Error('Mật khẩu không chính xác');
      case 'auth/too-many-requests':
        throw new Error('Quá nhiều lần thử. Vui lòng thử lại sau');
      default:
        throw new Error('Đăng nhập thất bại');
    }
  }
}

async function logOut() {
  await signOut(auth);
  console.log('Người dùng đã đăng xuất');
}

Đăng nhập bằng Google (Web):

import {
  GoogleAuthProvider,
  signInWithPopup
} from 'firebase/auth';

async function signInWithGoogle() {
  const provider = new GoogleAuthProvider();

  // Yêu cầu các phạm vi bổ sung
  provider.addScope('email');
  provider.addScope('profile');

  try {
    const result = await signInWithPopup(auth, provider);
    const user = result.user;

    // Truy cập mã thông báo OAuth của Google
    const credential = GoogleAuthProvider.credentialFromResult(result);
    const googleAccessToken = credential.accessToken;

    return user;
  } catch (error) {
    if (error.code === 'auth/popup-closed-by-user') {
      throw new Error('Đăng nhập đã bị hủy');
    }
    throw new Error('Đăng nhập bằng Google thất bại');
  }
}

Bước 5: Bảo vệ các tuyến đường với trạng thái xác thực

import { onAuthStateChanged } from 'firebase/auth';

// Đăng ký lắng nghe thay đổi trạng thái xác thực
onAuthStateChanged(auth, (user) => {
  if (user) {
    // Người dùng đã đăng nhập
    console.log('Người dùng:', user.email);
    // Chuyển hướng đến bảng điều khiển
    window.location.href = '/dashboard';
  } else {
    // Người dùng đã đăng xuất
    console.log('Không có người dùng nào');
    // Chuyển hướng đến trang đăng nhập
    window.location.href = '/login';
  }
});

Các lỗi xác thực thường gặp

Lỗi 1: Không xử lý làm mới mã thông báo

Firebase SDK tự động làm mới mã thông báo. Nhưng nếu bạn lưu trữ mã thông báo phía máy chủ, chúng sẽ hết hạn sau 1 giờ. Luôn xác minh mã thông báo trên mỗi yêu cầu hoặc triển khai logic làm mới.

Lỗi 2: Để lộ thông tin đăng nhập quản trị viên trong mã client

Không bao giờ sử dụng khóa tài khoản dịch vụ trong các ứng dụng client. Tài khoản dịch vụ bỏ qua các quy tắc bảo mật. Chỉ sử dụng chúng trong môi trường máy chủ đáng tin cậy.

Lỗi 3: Bỏ qua xác minh email

import { sendEmailVerification } from 'firebase/auth';

async function sendVerificationEmail(user) {
  await sendEmailVerification(user);
  console.log('Email xác minh đã được gửi');
}

// Kiểm tra trạng thái xác minh
if (!auth.currentUser.emailVerified) {
  console.log('Email chưa được xác minh');
  // Hạn chế quyền truy cập
}

Cơ sở dữ liệu Firestore: Các thao tác và Truy vấn

Firestore là cơ sở dữ liệu NoSQL của Firebase. Các tài liệu được tổ chức thành các bộ sưu tập. Các truy vấn tự động mở rộng.

Cấu trúc dữ liệu

your-project (gốc)
└── users (bộ sưu tập)
    ├── userId123 (tài liệu)
    │   ├── name: "John"
    │   ├── email: "john@example.com"
    │   └── posts (bộ sưu tập con)
    │       ├── postId1 (tài liệu)
    │       └── postId2 (tài liệu)
    └── userId456 (tài liệu)

Khởi tạo Firestore

import { getFirestore } from 'firebase/firestore';

const db = getFirestore(app);

Tạo tài liệu

import {
  collection,
  addDoc,
  setDoc,
  doc
} from 'firebase/firestore';

// Tùy chọn 1: ID tự động tạo
async function createUser(userData) {
  const docRef = await addDoc(collection(db, 'users'), userData);
  console.log('Tài liệu được ghi với ID:', docRef.id);
  return docRef.id;
}

// Tùy chọn 2: ID tùy chỉnh
async function createUserWithId(userId, userData) {
  await setDoc(doc(db, 'users', userId), userData);
  console.log('Tài liệu được ghi với ID tùy chỉnh:', userId);
}

// Cách sử dụng
const userId = await createUser({
  name: 'Alice',
  email: 'alice@example.com',
  createdAt: new Date(),
  role: 'user'
});

Đọc tài liệu

import {
  getDoc,
  getDocs,
  query,
  where,
  orderBy,
  limit
} from 'firebase/firestore';

// Lấy một tài liệu
async function getUser(userId) {
  const docRef = doc(db, 'users', userId);
  const docSnap = await getDoc(docRef);

  if (docSnap.exists()) {
    return docSnap.data();
  } else {
    throw new Error('Không tìm thấy người dùng');
  }
}

// Truy vấn với bộ lọc
async function getUsersByRole(role) {
  const q = query(
    collection(db, 'users'),
    where('role', '==', role),
    orderBy('createdAt', 'desc'),
    limit(10)
  );

  const querySnapshot = await getDocs(q);
  const users = [];

  querySnapshot.forEach((doc) => {
    users.push({ id: doc.id, ...doc.data() });
  });

  return users;
}

// Cách sử dụng
const adminUsers = await getUsersByRole('admin');
console.log('Người dùng quản trị:', adminUsers);

Cập nhật tài liệu

import {
  updateDoc,
  increment,
  arrayUnion,
  arrayRemove
} from 'firebase/firestore';

async function updateUser(userId, updates) {
  const userRef = doc(db, 'users', userId);
  await updateDoc(userRef, updates);
}

// Các thao tác nguyên tử
await updateUser('userId123', {
  loginCount: increment(1),
  tags: arrayUnion('premium', 'beta-tester'),
  lastLogin: new Date()
});

// Xóa khỏi mảng
await updateUser('userId123', {
  tags: arrayRemove('beta-tester')
});

Xóa tài liệu

import { deleteDoc } from 'firebase/firestore';

async function deleteUser(userId) {
  await deleteDoc(doc(db, 'users', userId));
  console.log('Người dùng đã bị xóa');
}

Trình lắng nghe thời gian thực

import { onSnapshot } from 'firebase/firestore';

// Lắng nghe một tài liệu
const unsubscribe = onSnapshot(
  doc(db, 'users', userId),
  (doc) => {
    console.log('Người dùng đã được cập nhật:', doc.data());
  },
  (error) => {
    console.error('Lỗi lắng nghe:', error);
  }
);

// Lắng nghe kết quả truy vấn
const q = query(collection(db, 'posts'), where('published', '==', true));

const unsubscribeQuery = onSnapshot(q, (snapshot) => {
  const posts = snapshot.docs.map(doc => ({
    id: doc.id,
    ...doc.data()
  }));
  console.log('Bài viết đã xuất bản:', posts);
});

// Ngừng lắng nghe
unsubscribe();
unsubscribeQuery();

Quy tắc bảo mật Firestore

Nếu không có quy tắc phù hợp, bất kỳ ai cũng có thể đọc dữ liệu của bạn. Đặt quy tắc trong Firebase Console > Firestore > Quy tắc:

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {

    // Hàm trợ giúp
    function isAuthenticated() {
      return request.auth != null;
    }

    function isOwner(userId) {
      return request.auth.uid == userId;
    }

    // Bộ sưu tập người dùng
    match /users/{userId} {
      allow read: if isAuthenticated();
      allow create: if isAuthenticated() && isOwner(userId);
      allow update, delete: if isOwner(userId);
    }

    // Bộ sưu tập bài viết
    match /posts/{postId} {
      allow read: if true; // Đọc công khai
      allow create: if isAuthenticated();
      allow update, delete: if resource.data.authorId == request.auth.uid;
    }

    // Bộ sưu tập con riêng tư
    match /users/{userId}/private/{document} {
      allow read, write: if isOwner(userId);
    }
  }
}

Hạn chế về truy vấn

Firestore có những ràng buộc:

Cách khắc phục cho các truy vấn OR:

// Thay vì: where('status', '==', 'active') OR where('status', '==', 'pending')

const activeQuery = query(
  collection(db, 'tasks'),
  where('status', '==', 'active')
);

const pendingQuery = query(
  collection(db, 'tasks'),
  where('status', '==', 'pending')
);

const [activeSnap, pendingSnap] = await Promise.all([
  getDocs(activeQuery),
  getDocs(pendingQuery)
]);

// Hợp nhất kết quả trong client

Cloud Functions: Logic Backend phi máy chủ

Cloud Functions chạy mã backend mà không cần quản lý máy chủ. Kích hoạt theo thay đổi cơ sở dữ liệu, yêu cầu HTTP hoặc các sự kiện đã lên lịch.

Thiết lập

# Cài đặt Firebase CLI
npm install -g firebase-tools

# Đăng nhập
firebase login

# Khởi tạo functions trong dự án của bạn
firebase init functions

# Chọn: JavaScript, ESLint yes, Express.js no

Hàm HTTP (Điểm cuối API)

// functions/index.js
const { onRequest } = require('firebase-functions/v2/https');
const admin = require('firebase-admin');

admin.initializeApp();
const db = admin.firestore();

// Điểm cuối công khai
exports.getPublicData = onRequest(async (req, res) => {
  res.set('Access-Control-Allow-Origin', '*');

  try {
    const snapshot = await db.collection('public').get();
    const data = snapshot.docs.map(doc => doc.data());
    res.json({ success: true, data });
  } catch (error) {
    res.status(500).json({ error: error.message });
  }
});

// Điểm cuối được bảo vệ (xác minh mã thông báo xác thực)
exports.getUserProfile = onRequest(async (req, res) => {
  res.set('Access-Control-Allow-Origin', '*');

  // Lấy mã thông báo từ tiêu đề Authorization
  const authHeader = req.headers.authorization || '';
  const token = authHeader.split('Bearer ')[1];

  if (!token) {
    return res.status(401).json({ error: 'Không được ủy quyền' });
  }

  try {
    // Xác minh mã thông báo
    const decodedToken = await admin.auth().verifyIdToken(token);
    const userId = decodedToken.uid;

    // Lấy dữ liệu người dùng
    const userDoc = await db.collection('users').doc(userId).get();

    if (!userDoc.exists) {
      return res.status(404).json({ error: 'Không tìm thấy người dùng' });
    }

    res.json({
      success: true,
      data: { id: userId, ...userDoc.data() }
    });
  } catch (error) {
    res.status(401).json({ error: 'Mã thông báo không hợp lệ' });
  }
});

Triển khai:

firebase deploy --only functions:getUserProfile

Gọi từ client:

async function getUserProfile(token) {
  const response = await fetch(
    'https://us-central1-your-app.cloudfunctions.net/getUserProfile',
    {
      headers: {
        'Authorization': `Bearer ${token}`
      }
    }
  );

  const data = await response.json();
  return data;
}

Kích hoạt cơ sở dữ liệu

const { onDocumentWritten } = require('firebase-functions/v2/firestore');

// Kích hoạt khi tài liệu người dùng thay đổi
exports.onUserUpdate = onDocumentWritten(
  'users/{userId}',
  async (event) => {
    const userId = event.params.userId;
    const before = event.data?.before?.data();
    const after = event.data?.after?.data();

    // Kiểm tra nếu email thay đổi
    if (before?.email !== after?.email) {
      console.log(`Email người dùng ${userId} đã thay đổi: ${before?.email} → ${after?.email}`);

      // Gửi email thông báo
      await admin.auth().getUser(userId);
      // Thêm logic email của bạn ở đây
    }
  }
);

// Kích hoạt khi tạo bài viết mới
exports.onNewPost = onDocumentWritten(
  'posts/{postId}',
  async (event) => {
    const post = event.data?.after?.data();

    if (!post) return; // Tài liệu đã bị xóa

    // Kiểm tra xem đây có phải là tài liệu mới không
    if (!event.data?.before?.exists) {
      console.log('Bài viết mới được tạo:', post.title);

      // Thông báo cho người theo dõi
      const followersSnap = await admin.firestore()
        .collection('users')
        .where('following', 'array-contains', post.authorId)
        .get();

      const notifications = followersSnap.docs.map(doc => ({
        userId: doc.id,
        postId: event.params.postId,
        type: 'new_post',
        createdAt: admin.firestore.FieldValue.serverTimestamp()
      }));

      const batch = admin.firestore().batch();
      notifications.forEach(notif => {
        const ref = admin.firestore().collection('notifications').doc();
        batch.set(ref, notif);
      });

      await batch.commit();
    }
  }
);

Hàm được lên lịch (Cron Jobs)

const { onSchedule } = require('firebase-functions/v2/scheduler');

// Chạy mỗi ngày vào nửa đêm UTC
exports.dailyCleanup = onSchedule('every 24 hours', async (event) => {
  console.log('Đang chạy dọn dẹp hàng ngày');

  // Xóa các thông báo cũ (hơn 30 ngày)
  const thirtyDaysAgo = new Date();
  thirtyDaysAgo.setDate(thirtyDaysAgo.getDate() - 30);

  const oldNotifs = await admin.firestore()
    .collection('notifications')
    .where('createdAt', '<', thirtyDaysAgo)
    .get();

  const batch = admin.firestore().batch();
  oldNotifs.forEach(doc => batch.delete(doc.ref));
  await batch.commit();

  console.log(`Đã xóa ${oldNotifs.size} thông báo cũ`);
});

Cấu hình môi trường

# Đặt biến môi trường
firebase functions:config:set \
  stripe.secret="sk_test_xxx" \
  email.api_key="key_xxx"

# Truy cập trong các hàm
const config = require('firebase-functions/config');
const stripe = require('stripe')(config.stripe.secret);

Cloud Storage: Tải lên và Quản lý tệp

Lưu trữ các tệp tải lên của người dùng, hình ảnh và tệp với phân phối CDN tự động.

Thiết lập Quy tắc Storage

// Firebase Console > Storage > Rules
rules_version = '2';
service firebase.storage {
  match /b/{bucket}/o {

    // Thư mục tải lên của người dùng
    match /users/{userId}/{allPaths=**} {
      allow read: if true; // Đọc công khai
      allow write: if request.auth.uid == userId;
      allow delete: if request.auth.uid == userId;
    }

    // Tài sản công khai
    match /public/{allPaths=**} {
      allow read: if true;
      allow write: if false; // Chỉ quản trị viên thông qua Firebase Console
    }
  }
}

Tải lên tệp (Client)

import {
  getStorage,
  ref,
  uploadBytesResumable,
  getDownloadURL
} from 'firebase/storage';

const storage = getStorage(app);

async function uploadProfileImage(userId, file) {
  // Tạo tham chiếu lưu trữ
  const storageRef = ref(storage, `users/${userId}/profile/${file.name}`);

  // Tải lên tệp
  const uploadTask = uploadBytesResumable(storageRef, file);

  return new Promise((resolve, reject) => {
    uploadTask.on(
      'state_changed',
      (snapshot) => {
        // Theo dõi tiến độ
        const progress = (snapshot.bytesTransferred / snapshot.totalBytes) * 100;
        console.log(`Tải lên: ${progress.toFixed(0)}%`);
      },
      (error) => {
        // Xử lý lỗi
        switch (error.code) {
          case 'storage/unauthorized':
            reject(new Error('Bạn không có quyền'));
            break;
          case 'storage/canceled':
            reject(new Error('Tải lên đã bị hủy'));
            break;
          default:
            reject(new Error('Tải lên thất bại'));
        }
      },
      async () => {
        // Tải lên hoàn tất
        const downloadURL = await getDownloadURL(uploadTask.snapshot.ref);
        console.log('Tệp có sẵn tại:', downloadURL);
        resolve(downloadURL);
      }
    );
  });
}

// Cách sử dụng
const fileInput = document.querySelector('input[type="file"]');
const file = fileInput.files[0];

if (file) {
  const imageUrl = await uploadProfileImage(auth.currentUser.uid, file);

  // Lưu URL vào Firestore
  await updateDoc(doc(db, 'users', auth.currentUser.uid), {
    profileImage: imageUrl
  });
}

Tải xuống tệp

import { getDownloadURL } from 'firebase/storage';

async function getProfileImage(userId) {
  const imageRef = ref(storage, `users/${userId}/profile/avatar.png`);

  try {
    const url = await getDownloadURL(imageRef);
    return url;
  } catch (error) {
    if (error.code === 'storage/object-not-found') {
      return null; // Không có hình ảnh hồ sơ
    }
    throw error;
  }
}

Xóa tệp

import { deleteObject } from 'firebase/storage';

async function deleteProfileImage(userId) {
  const imageRef = ref(storage, `users/${userId}/profile/avatar.png`);
  await deleteObject(imageRef);
  console.log('Ảnh đại diện đã bị xóa');
}

Kiểm thử API Firebase với Apidog

Firebase cung cấp các API REST cho tất cả các dịch vụ. Kiểm thử chúng trực tiếp giúp gỡ lỗi các vấn đề và hiểu các yêu cầu cơ bản.

Nhập API REST Firebase

  1. Mở Apidog
  2. Tạo dự án mới: “Firebase API”
  3. Nhập thông số kỹ thuật OpenAPI từ tài liệu Firebase
  4. Hoặc thêm điểm cuối theo cách thủ công:

Điểm cuối REST Firestore:

POST https://firestore.googleapis.com/v1/projects/{projectId}/databases/(default)/documents
Authorization: Bearer {oauth2_token}
Content-Type: application/json

{
  "fields": {
    "name": { "stringValue": "John" },
    "email": { "stringValue": "john@example.com" },
    "age": { "integerValue": 30 }
  }
}

Điểm cuối xác thực:

POST https://identitytoolkit.googleapis.com/v1/accounts:signInWithPassword?key={api_key}
Content-Type: application/json

{
  "email": "user@example.com",
  "password": "secret123",
  "returnSecureToken": true
}

Kiểm thử luồng xác thực

  1. Tạo yêu cầu: “Đăng nhập”
  2. Đặt phương thức: POST
  3. Thêm email/mật khẩu vào phần thân
  4. Lưu mã thông báo phản hồi dưới dạng biến môi trường
  5. Sử dụng {{token}} trong các yêu cầu tiếp theo

Gỡ lỗi quy tắc bảo mật

Sử dụng Firebase Emulator Suite để kiểm thử cục bộ:

# Khởi động emulator
firebase emulators:start

# Kiểm thử với Firestore cục bộ
# http://localhost:8080

Các Thực hành Tốt nhất trong Sản xuất

1. Triển khai Xử lý lỗi thích hợp

// Logic thử lại cho các lỗi tạm thời
async function firestoreWithRetry(operation, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    try {
      return await operation();
    } catch (error) {
      if (
        error.code === 'unavailable' ||
        error.code === 'deadline-exceeded'
      ) {
        const delay = Math.pow(2, i) * 1000; // Quay lại theo cấp số nhân
        await new Promise(resolve => setTimeout(resolve, delay));
        continue;
      }
      throw error;
    }
  }
}

2. Tối ưu hóa hiệu suất truy vấn

Thêm chỉ mục tổng hợp cho các truy vấn đa trường:

// Truy vấn này cần một chỉ mục tổng hợp
const q = query(
  collection(db, 'posts'),
  where('category', '==', 'tech'),
  where('views', '>', 1000),
  orderBy('views', 'desc')
);

Firestore nhắc bạn tạo chỉ mục với một liên kết trực tiếp khi bạn chạy truy vấn này.

3. Các thao tác hàng loạt

import { writeBatch } from 'firebase/firestore';

async function bulkUpdate(userIds, updates) {
  const batch = writeBatch(db);

  userIds.forEach(id => {
    const ref = doc(db, 'users', id);
    batch.update(ref, updates);
  });

  await batch.commit();
  console.log(`Đã cập nhật ${userIds.length} người dùng`);
}

// Tối đa 500 thao tác mỗi batch

4. Giám sát chi phí

Giá Firebase:

Dịch vụ Gói miễn phí Trả phí
Firestore 50K lượt đọc/ngày $0.036/100K lượt đọc
Storage 5GB $0.023/GB
Functions 2M lượt gọi $0.40/1M
Auth 10K/tháng $0.0055/100K

Đặt cảnh báo ngân sách trong Google Cloud Console.

5. Bảo mật tài khoản dịch vụ

// SAI: Không bao giờ làm điều này trong mã client
admin.initializeApp({
  credential: admin.credential.cert(require('./serviceAccountKey.json'))
});

// ĐÚNG: Chỉ sử dụng trong môi trường máy chủ
const serviceAccount = JSON.parse(process.env.FIREBASE_SERVICE_ACCOUNT);
admin.initializeApp({
  credential: admin.credential.cert(serviceAccount)
});

6. Xử lý các kịch bản ngoại tuyến

// Bật tính năng bền vững ngoại tuyến (web)
import { enableMultiTabIndexedDbPersistence } from 'firebase/firestore';

enableMultiTabIndexedDbPersistence(db)
  .catch((err) => {
    if (err.code === 'failed-precondition') {
      // Nhiều tab đang mở
    } else if (err.code === 'unimplemented') {
      // Trình duyệt không hỗ trợ
    }
  });

// Lắng nghe kết nối
import { onSnapshot } from 'firebase/firestore';

onSnapshot(doc(db, 'status', 'online'), (doc) => {
  if (!doc.exists()) {
    console.log('Bạn đang ngoại tuyến');
    // Hiển thị giao diện ngoại tuyến
  }
});

Các vấn đề và Giải pháp API Firebase Thường gặp

Vấn đề 1: Lỗi từ chối quyền

Triệu chứng: Lỗi: 7 PERMISSION_DENIED

Nguyên nhân: Các quy tắc bảo mật chặn thao tác

Cách khắc phục:

  1. Kiểm tra quy tắc trong Firebase Console
  2. Xác minh request.auth.uid khớp với người dùng mong muốn
  3. Kiểm thử quy tắc bằng Rules Playground

Vấn đề 2: Mã thông báo hết hạn

Triệu chứng: Lỗi: Mã thông báo ID đã hết hạn

Cách khắc phục:

// Buộc làm mới mã thông báo
const user = auth.currentUser;
if (user) {
  await user.getIdToken(true); // Buộc làm mới
}

Vấn đề 3: Độ trễ khởi động nguội

Triệu chứng: Cloud Functions mất 2-5 giây trong lần gọi đầu tiên

Cách khắc phục:

// Giữ cho các hàm luôn "ấm" bằng các ping theo lịch trình
exports.keepWarm = onSchedule('every 60 seconds', async () => {
  await fetch('https://your-function.cloudfunctions.net/health');
});

Vấn đề 4: Truy vấn trả về kết quả trống

Triệu chứng: Truy vấn lẽ ra phải trả về dữ liệu nhưng lại trả về mảng trống

Nguyên nhân: Thiếu chỉ mục hoặc thứ tự trường sai

Cách khắc phục: Kiểm tra Firestore Console > Indexes để tìm các chỉ mục tổng hợp cần thiết.

Các trường hợp sử dụng thực tế

Ứng dụng Fintech: Cập nhật giao dịch thời gian thực

Một công ty khởi nghiệp thanh toán đã sử dụng Firebase Firestore để xây dựng các thông báo giao dịch thời gian thực. Khi một khoản thanh toán được xử lý, Cloud Functions kích hoạt cập nhật đến tất cả các bảng điều khiển quản trị viên được kết nối trong vòng 200ms. Kết quả: Giảm 40% số lượng yêu cầu hỗ trợ về các giao dịch "đang chờ xử lý".

Thương mại điện tử: Đồng bộ hóa kho hàng

Một nhà bán lẻ trực tuyến đồng bộ hóa kho hàng trên web, iOS và Android bằng cách sử dụng trình lắng nghe Firestore. Khi kho hàng thay đổi, tất cả các client tự động cập nhật. Tính năng bền vững ngoại tuyến đảm bảo nhân viên kho có thể quét các mặt hàng mà không cần kết nối, với tính năng đồng bộ hóa tự động khi được kết nối lại.

SaaS: Xác thực đa khách thuê

Một nền tảng B2B sử dụng Firebase Auth với các xác nhận tùy chỉnh cho quyền truy cập dựa trên vai trò. Người dùng quản trị nhận được các quyền nâng cao thông qua Cloud Functions xác thực dựa trên cấu hình khách thuê Firestore. Một codebase duy nhất phục vụ hơn 500 tổ chức với dữ liệu được cô lập.

Kết luận

Tích hợp API Firebase liên quan đến bốn dịch vụ cốt lõi:

Bạn đã học về các luồng xác thực, các thao tác cơ sở dữ liệu, triển khai hàm và quản lý tệp. Bạn đã thấy các mẫu sản xuất: xử lý lỗi, nhóm, hỗ trợ ngoại tuyến và bảo mật.

nút

FAQ

Firebase có miễn phí để sử dụng không?

Có, Firebase có một gói miễn phí hào phóng (Spark Plan) bao gồm 5GB lưu trữ, 50K lượt đọc Firestore/ngày, 2M lượt gọi Cloud Function và 10K người dùng Auth/tháng. Các gói trả phí (Blaze) sử dụng giá trả theo mức sử dụng.

Tôi có thể sử dụng Firebase với các cơ sở dữ liệu hiện có không?

Có. Sử dụng Firebase Extensions để đồng bộ hóa với PostgreSQL, MySQL hoặc MongoDB. Hoặc gọi các API bên ngoài từ Cloud Functions để tích hợp với các hệ thống hiện có.

Làm cách nào để di chuyển từ Firebase sang nền tảng khác?

Xuất dữ liệu bằng các chức năng xuất của Firestore hoặc Firebase CLI. Đối với các tập dữ liệu lớn, hãy sử dụng quy trình xuất Dataflow. Độ phức tạp của việc di chuyển phụ thuộc vào cấu trúc dữ liệu của bạn.

Firebase có hỗ trợ GraphQL không?

Không natively. Sử dụng các giải pháp của bên thứ ba như firestore-graphql hoặc xây dựng một lớp GraphQL bằng Cloud Functions và Apollo Server.

Tôi có thể sử dụng Firebase tại chỗ không?

Không. Firebase chỉ dành cho Google Cloud. Đối với các lựa chọn thay thế tự lưu trữ, hãy cân nhắc Appwrite, Supabase hoặc Nhost.

Làm cách nào để xử lý các tệp tải lên lớn hơn 100MB?

Sử dụng tính năng tải lên có thể tiếp tục với chia nhỏ tệp (chunking). Firebase SDK tự động xử lý việc này. Đối với các tệp rất lớn, hãy sử dụng Google Cloud Storage trực tiếp với các URL được ký.

Điều gì sẽ xảy ra nếu tôi vượt quá giới hạn truy vấn Firestore?

Các truy vấn sẽ thất bại với lỗi FAILED_PRECONDITION. Thêm các chỉ mục cần thiết hoặc cấu trúc lại các truy vấn. Firestore cung cấp các liên kết trực tiếp để tạo các chỉ mục còn thiếu trong thông báo lỗi.

Firebase có tuân thủ GDPR không?

Có, Firebase cung cấp khả năng xử lý dữ liệu tuân thủ GDPR. Bật tính năng lưu trữ dữ liệu ở các khu vực cụ thể, triển khai xuất/xóa dữ liệu người dùng và ký Thỏa thuận Xử lý Dữ liệu của Google.

Thực hành thiết kế API trong Apidog

Khám phá cách dễ dàng hơn để xây dựng và sử dụng API