Firebase 教程

1. 什么是 Firebase?

Firebase 是 Google 提供的后端即服务 (BaaS) 平台,它允许开发者快速构建、部署和扩展应用,而无需管理服务器基础设施。Firebase 提供了一系列服务,包括实时数据库、认证、云存储、云函数、托管等。

2. Firebase 的核心概念

2.1 项目 (Project)

项目是 Firebase 资源的组织单元,每个 Firebase 资源都属于一个项目。

2.2 实时数据库 (Realtime Database)

实时数据库是一个 NoSQL 云数据库,它允许数据在客户端之间实时同步。

2.3 Cloud Firestore

Cloud Firestore 是 Firebase 的新一代数据库,它提供了更强大的查询能力、更灵活的数据模型和更好的扩展性。

2.4 认证 (Authentication)

认证服务允许用户通过电子邮件/密码、电话号码、社交媒体账号等方式登录应用。

2.5 云存储 (Cloud Storage)

云存储服务允许用户上传和下载文件,如图片、视频、音频等。

2.6 云函数 (Cloud Functions)

云函数是托管在 Firebase 上的无服务器函数,它可以响应 Firebase 事件或 HTTP 请求。

2.7 托管 (Hosting)

托管服务允许开发者部署和托管静态网站和单页应用。

2.8 分析 (Analytics)

分析服务允许开发者跟踪用户行为和应用性能。

3. Firebase 的安装和配置

3.1 创建 Firebase 项目

  1. 访问 Firebase 控制台
  2. 点击 "添加项目"
  3. 输入项目名称并点击 "继续"
  4. 选择是否启用 Google Analytics(可选)
  5. 点击 "创建项目"

3.2 安装 Firebase SDK

使用 npm 或 yarn 安装 Firebase SDK:

# 安装 Firebase 核心包
npm install firebase

# 安装 Firebase Admin SDK(用于服务器端)
npm install firebase-admin

3.3 初始化 Firebase

客户端初始化:

// 引入 Firebase 核心模块
import { initializeApp } from "firebase/app";
import { getAuth } from "firebase/auth";
import { getFirestore } from "firebase/firestore";
import { getStorage } from "firebase/storage";

// Firebase 配置
const firebaseConfig = {
  apiKey: "your-api-key",
  authDomain: "your-project-id.firebaseapp.com",
  projectId: "your-project-id",
  storageBucket: "your-project-id.appspot.com",
  messagingSenderId: "your-messaging-sender-id",
  appId: "your-app-id",
  measurementId: "your-measurement-id"
};

// 初始化 Firebase
const app = initializeApp(firebaseConfig);

// 获取服务实例
const auth = getAuth(app);
const db = getFirestore(app);
const storage = getStorage(app);

服务器端初始化:

// 引入 Firebase Admin SDK
const admin = require('firebase-admin');

// 初始化 Firebase Admin SDK
admin.initializeApp({
  credential: admin.credential.cert(require('./service-account-key.json'))
});

// 获取服务实例
const auth = admin.auth();
const db = admin.firestore();
const storage = admin.storage();

4. Firebase 的基本使用

4.1 使用认证服务

创建用户:

import { createUserWithEmailAndPassword } from "firebase/auth";

async function createUser(email, password) {
  try {
    const userCredential = await createUserWithEmailAndPassword(auth, email, password);
    const user = userCredential.user;
    console.log('User created:', user.uid);
    return user;
  } catch (error) {
    console.error('Error creating user:', error);
    throw error;
  }
}

// 使用示例
createUser('user@example.com', 'password123');

用户登录:

import { signInWithEmailAndPassword } from "firebase/auth";

async function loginUser(email, password) {
  try {
    const userCredential = await signInWithEmailAndPassword(auth, email, password);
    const user = userCredential.user;
    console.log('User logged in:', user.uid);
    return user;
  } catch (error) {
    console.error('Error logging in:', error);
    throw error;
  }
}

// 使用示例
loginUser('user@example.com', 'password123');

用户登出:

import { signOut } from "firebase/auth";

async function logoutUser() {
  try {
    await signOut(auth);
    console.log('User logged out');
  } catch (error) {
    console.error('Error logging out:', error);
    throw error;
  }
}

// 使用示例
logoutUser();

4.2 使用 Cloud Firestore

添加文档:

import { collection, addDoc } from "firebase/firestore";

async function addDocument(collectionName, data) {
  try {
    const docRef = await addDoc(collection(db, collectionName), data);
    console.log('Document written with ID:', docRef.id);
    return docRef;
  } catch (error) {
    console.error('Error adding document:', error);
    throw error;
  }
}

// 使用示例
addDocument('users', {
  name: 'John Doe',
  email: 'john@example.com',
  age: 30,
  createdAt: new Date()
});

读取文档:

import { doc, getDoc } from "firebase/firestore";

async function getDocument(collectionName, documentId) {
  try {
    const docRef = doc(db, collectionName, documentId);
    const docSnap = await getDoc(docRef);
    
    if (docSnap.exists()) {
      console.log('Document data:', docSnap.data());
      return docSnap.data();
    } else {
      console.log('No such document!');
      return null;
    }
  } catch (error) {
    console.error('Error getting document:', error);
    throw error;
  }
}

// 使用示例
getDocument('users', 'document-id');

查询文档:

import { collection, query, where, orderBy, limit, getDocs } from "firebase/firestore";

async function queryDocuments(collectionName) {
  try {
    const q = query(
      collection(db, collectionName),
      where('age', '>', 25),
      orderBy('age', 'desc'),
      limit(5)
    );
    
    const querySnapshot = await getDocs(q);
    const documents = [];
    
    querySnapshot.forEach((doc) => {
      documents.push({ id: doc.id, ...doc.data() });
    });
    
    console.log('Documents found:', documents.length);
    return documents;
  } catch (error) {
    console.error('Error querying documents:', error);
    throw error;
  }
}

// 使用示例
queryDocuments('users');

实时监听文档:

import { doc, onSnapshot } from "firebase/firestore";

function listenToDocument(collectionName, documentId) {
  const docRef = doc(db, collectionName, documentId);
  
  const unsubscribe = onSnapshot(docRef, (docSnap) => {
    if (docSnap.exists()) {
      console.log('Current document data:', docSnap.data());
    } else {
      console.log('Document does not exist');
    }
  });
  
  // 稍后取消监听
  // unsubscribe();
}

// 使用示例
listenToDocument('users', 'document-id');

4.3 使用云存储服务

上传文件:

import { ref, uploadBytes, getDownloadURL } from "firebase/storage";

async function uploadFile(file, storagePath) {
  try {
    const storageRef = ref(storage, storagePath);
    await uploadBytes(storageRef, file);
    
    const downloadURL = await getDownloadURL(storageRef);
    console.log('File uploaded successfully:', downloadURL);
    return downloadURL;
  } catch (error) {
    console.error('Error uploading file:', error);
    throw error;
  }
}

// 使用示例
const fileInput = document.getElementById('file-input');
uploadFile(fileInput.files[0], 'images/profile.jpg');

下载文件:

import { ref, getDownloadURL } from "firebase/storage";

async function downloadFile(storagePath) {
  try {
    const storageRef = ref(storage, storagePath);
    const downloadURL = await getDownloadURL(storageRef);
    console.log('File URL:', downloadURL);
    return downloadURL;
  } catch (error) {
    console.error('Error getting file URL:', error);
    throw error;
  }
}

// 使用示例
downloadFile('images/profile.jpg');

删除文件:

import { ref, deleteObject } from "firebase/storage";

async function deleteFile(storagePath) {
  try {
    const storageRef = ref(storage, storagePath);
    await deleteObject(storageRef);
    console.log('File deleted successfully');
  } catch (error) {
    console.error('Error deleting file:', error);
    throw error;
  }
}

// 使用示例
deleteFile('images/profile.jpg');

4.4 使用云函数

创建云函数:

  1. 安装 Firebase CLI:npm install -g firebase-tools
  2. 登录 Firebase:firebase login
  3. 初始化云函数:firebase init functions
  4. functions/index.js 文件中编写云函数:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();

// HTTP 云函数
exports.helloWorld = functions.https.onRequest((request, response) => {
  response.send('Hello from Firebase!');
});

// 实时数据库触发器云函数
exports.newMessage = functions.database.ref('/messages/{messageId}')
  .onCreate((snapshot, context) => {
    const message = snapshot.val();
    console.log('New message:', message);
    return null;
  });

// Firestore 触发器云函数
exports.newUser = functions.firestore.document('/users/{userId}')
  .onCreate((snapshot, context) => {
    const user = snapshot.data();
    console.log('New user:', user);
    return null;
  });

// 认证触发器云函数
exports.userCreated = functions.auth.user()
  .onCreate((user) => {
    console.log('User created:', user.uid);
    return null;
  });
  1. 部署云函数:firebase deploy --only functions

5. Firebase 的高级功能

5.1 使用 Firebase 托管

Firebase 托管允许开发者部署和托管静态网站和单页应用:

  1. 初始化托管:firebase init hosting
  2. 构建应用:npm run build
  3. 部署应用:firebase deploy --only hosting

5.2 使用 Firebase 分析

Firebase 分析允许开发者跟踪用户行为和应用性能:

import { getAnalytics, logEvent } from "firebase/analytics";

// 获取分析实例
const analytics = getAnalytics(app);

// 记录事件
logEvent(analytics, 'login', {
  method: 'email'
});

logEvent(analytics, 'purchase', {
  items: [{
    item_id: '1',
    item_name: 'Product 1',
    price: 9.99
  }],
  value: 9.99,
  currency: 'USD'
});

5.3 使用 Firebase 远程配置

远程配置允许开发者动态更改应用的行为和外观,而无需发布应用更新:

import { getRemoteConfig, fetchAndActivate } from "firebase/remote-config";

// 获取远程配置实例
const remoteConfig = getRemoteConfig(app);

// 设置默认值
remoteConfig.defaultConfig = {
  'welcome_message': 'Welcome to our app!',
  'feature_enabled': false,
  'discount_percentage': 10
};

// 获取配置
async function getRemoteConfigValues() {
  try {
    await fetchAndActivate(remoteConfig);
    
    const welcomeMessage = remoteConfig.getValue('welcome_message').asString();
    const featureEnabled = remoteConfig.getValue('feature_enabled').asBoolean();
    const discountPercentage = remoteConfig.getValue('discount_percentage').asNumber();
    
    console.log('Remote config values:', {
      welcomeMessage,
      featureEnabled,
      discountPercentage
    });
    
    return {
      welcomeMessage,
      featureEnabled,
      discountPercentage
    };
  } catch (error) {
    console.error('Error getting remote config:', error);
    throw error;
  }
}

// 使用示例
getRemoteConfigValues();

5.4 使用 Firebase 云消息传递

云消息传递允许开发者向用户发送通知:

// 服务器端发送消息
const admin = require('firebase-admin');

async function sendNotification(token, title, body) {
  try {
    const message = {
      notification: {
        title,
        body
      },
      token
    };
    
    const response = await admin.messaging().send(message);
    console.log('Notification sent:', response);
    return response;
  } catch (error) {
    console.error('Error sending notification:', error);
    throw error;
  }
}

// 使用示例
sendNotification('device-token', 'Hello', 'This is a notification from Firebase!');

6. Firebase 的最佳实践

6.1 安全最佳实践

  • 使用 Firebase 安全规则:为数据库和存储设置适当的安全规则
  • 验证用户输入:在客户端和服务器端验证用户输入
  • 使用 HTTPS:确保所有通信都使用 HTTPS
  • 保护服务账号密钥:不要将服务账号密钥提交到版本控制系统

6.2 性能最佳实践

  • 使用批量写入:对于多个数据库操作,使用批量写入减少网络往返
  • 使用缓存:缓存频繁访问的数据
  • 优化查询:使用适当的索引和查询条件
  • 限制数据传输:只获取必要的数据

6.3 成本最佳实践

  • 监控使用情况:定期检查 Firebase 使用情况和成本
  • 设置预算警报:为项目设置预算警报
  • 优化数据库操作:减少不必要的数据库读取和写入
  • 使用适当的存储类型:根据数据访问模式选择合适的存储类型

6.4 代码组织最佳实践

  • 模块化:将 Firebase 服务相关代码组织成模块
  • 使用异步/await:使用现代 JavaScript 语法处理异步操作
  • 编写单元测试:为 Firebase 代码编写单元测试
  • 使用 TypeScript:使用 TypeScript 提高代码可靠性

7. 实际应用示例

7.1 构建一个实时聊天应用

import { collection, addDoc, onSnapshot, query, orderBy } from "firebase/firestore";

// 发送消息
async function sendMessage(text, userId, userName) {
  try {
    await addDoc(collection(db, 'messages'), {
      text,
      userId,
      userName,
      timestamp: new Date()
    });
  } catch (error) {
    console.error('Error sending message:', error);
  }
}

// 监听消息
function listenToMessages(callback) {
  const q = query(
    collection(db, 'messages'),
    orderBy('timestamp', 'asc')
  );
  
  return onSnapshot(q, (querySnapshot) => {
    const messages = [];
    querySnapshot.forEach((doc) => {
      messages.push(doc.data());
    });
    callback(messages);
  });
}

// 使用示例
const unsubscribe = listenToMessages((messages) => {
  console.log('Messages:', messages);
  // 更新 UI
});

// 发送消息
sendMessage('Hello everyone!', 'user1', 'John Doe');

7.2 构建一个用户认证系统

import { 
  createUserWithEmailAndPassword, 
  signInWithEmailAndPassword, 
  signOut, 
  onAuthStateChanged 
} from "firebase/auth";

// 注册用户
async function register(email, password) {
  try {
    await createUserWithEmailAndPassword(auth, email, password);
    console.log('User registered successfully');
  } catch (error) {
    console.error('Error registering user:', error);
  }
}

// 登录用户
async function login(email, password) {
  try {
    await signInWithEmailAndPassword(auth, email, password);
    console.log('User logged in successfully');
  } catch (error) {
    console.error('Error logging in:', error);
  }
}

// 登出用户
async function logout() {
  try {
    await signOut(auth);
    console.log('User logged out successfully');
  } catch (error) {
    console.error('Error logging out:', error);
  }
}

// 监听认证状态变化
function listenToAuthState(callback) {
  return onAuthStateChanged(auth, (user) => {
    callback(user);
  });
}

// 使用示例
const unsubscribe = listenToAuthState((user) => {
  if (user) {
    console.log('User is signed in:', user.uid);
    // 更新 UI 显示已登录状态
  } else {
    console.log('User is signed out');
    // 更新 UI 显示已登出状态
  }
});

7.3 构建一个文件上传系统

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

// 上传文件(带进度)
async function uploadFileWithProgress(file, storagePath, onProgress) {
  try {
    const storageRef = ref(storage, storagePath);
    const uploadTask = uploadBytesResumable(storageRef, file);
    
    // 监听上传进度
    uploadTask.on('state_changed', (snapshot) => {
      const progress = (snapshot.bytesTransferred / snapshot.totalBytes) * 100;
      onProgress(progress);
    });
    
    // 等待上传完成
    await uploadTask;
    
    // 获取下载 URL
    const downloadURL = await getDownloadURL(storageRef);
    console.log('File uploaded successfully:', downloadURL);
    return downloadURL;
  } catch (error) {
    console.error('Error uploading file:', error);
    throw error;
  }
}

// 使用示例
const fileInput = document.getElementById('file-input');
uploadFileWithProgress(
  fileInput.files[0],
  'images/profile.jpg',
  (progress) => {
    console.log('Upload progress:', progress);
    // 更新进度条
  }
).then((downloadURL) => {
  console.log('File URL:', downloadURL);
  // 保存文件 URL 到数据库
});

8. Firebase 与其他 BaaS 平台的比较

8.1 Firebase vs Supabase

  • 数据模型:Firebase 使用实时数据库和 Firestore,而 Supabase 使用 PostgreSQL
  • 开源:Supabase 是开源的,而 Firebase 是闭源的
  • 定价:Supabase 提供更慷慨的免费额度,而 Firebase 按使用量计费
  • 功能:两者都提供类似的功能,包括认证、存储、函数等

8.2 Firebase vs AWS Amplify

  • 生态系统:Firebase 是一个完整的 BaaS 平台,而 AWS Amplify 是 AWS 服务的集合
  • 灵活性:AWS Amplify 提供更多的 AWS 服务集成,而 Firebase 提供更简单的使用体验
  • 定价:两者都按使用量计费,但具体定价模型不同
  • 部署:Firebase 部署更简单,而 AWS Amplify 提供更多的部署选项

9. 总结

Firebase 是一个强大的后端即服务 (BaaS) 平台,它允许开发者快速构建、部署和扩展应用,而无需管理服务器基础设施。通过本教程的学习,你应该已经掌握了 Firebase 的核心概念、安装配置、基本使用和高级功能。

Firebase 的主要优势包括:

  • 实时数据同步:实时数据库和 Firestore 允许数据在客户端之间实时同步
  • 易于使用:提供了简单易用的 API,减少了开发时间
  • 完整的服务套件:提供了一系列服务,包括认证、存储、函数、托管等
  • 可扩展性:自动扩展以满足应用的需求
  • 强大的生态系统:与 Google Cloud 服务集成良好

通过遵循最佳实践,你可以构建安全、高性能、可靠的 Firebase 应用。无论是构建 Web 应用、移动应用还是游戏,Firebase 都能为你提供强大的支持。

« 上一篇 Google Cloud SDK 教程 下一篇 » Supabase 教程