📚 课程目标

本课将深入讲解CloudBase云函数的开发、部署和优化。你将学会如何设计云函数架构、实现业务逻辑、处理错误、记录日志,以及如何高效地部署和测试云函数。

🏗️ 云函数架构设计

架构原则

  1. 单一职责:每个云函数只负责一个业务模块
  2. 统一入口:通过action参数路由不同功能
  3. 错误处理:统一的错误捕获和返回格式
  4. 日志记录:完整的操作日志便于调试

云函数调用关系图

💻 云函数标准模板

1. 基础结构模板

// cloudfunctions/pet_service_template/index.js
const cloud = require('wx-server-sdk');

// 初始化云开发环境
cloud.init({
  env: cloud.DYNAMIC_CURRENT_ENV // 使用当前云环境
});

// 获取数据库引用
const db = cloud.database();
const _ = db.command;

/**
 * 云函数入口
 * @param {Object} event - 前端传入的参数
 * @param {Object} context - 云函数上下文
 */
exports.main = async (event, context) => {
  // 获取调用者信息
  const { OPENID, APPID, UNIONID } = cloud.getWXContext();
  
  // 记录请求日志
  console.log('[CloudFunction] 请求开始', {
    action: event.action,
    openid: OPENID,
    timestamp: new Date().toISOString()
  });
  
  try {
    // 路由到具体处理函数
    const result = await routeAction(event, context);
    
    // 记录成功日志
    console.log('[CloudFunction] 请求成功', {
      action: event.action,
      success: true
    });
    
    return {
      success: true,
      data: result,
      timestamp: new Date().toISOString()
    };
    
  } catch (error) {
    // 记录错误日志
    console.error('[CloudFunction] 请求失败', {
      action: event.action,
      error: error.message,
      stack: error.stack
    });
    
    return {
      success: false,
      error: error.message,
      code: error.code || 'UNKNOWN_ERROR',
      timestamp: new Date().toISOString()
    };
  }
};

/**
 * 路由函数
 */
async function routeAction(event, context) {
  const { action } = event;
  
  // 验证action参数
  if (!action) {
    throw new Error('缺少action参数');
  }
  
  // 根据action路由到不同处理函数
  switch (action) {
    case 'create':
      return await handleCreate(event);
    case 'update':
      return await handleUpdate(event);
    case 'delete':
      return await handleDelete(event);
    case 'query':
      return await handleQuery(event);
    case 'list':
      return await handleList(event);
    default:
      throw new Error(`未知的action: ${action}`);
  }
}

/**
 * 处理创建操作
 */
async function handleCreate(event) {
  const { data } = event;
  
  // 数据验证
  validateData(data);
  
  // 添加时间戳
  const recordData = {
    ...data,
    created_time: new Date(),
    updated_time: new Date()
  };
  
  // 插入数据库
  const result = await db.collection('your_collection').add({
    data: recordData
  });
  
  console.log('[handleCreate] 创建成功', { id: result._id });
  
  return {
    id: result._id,
    message: '创建成功'
  };
}

/**
 * 处理更新操作
 */
async function handleUpdate(event) {
  const { id, data } = event;
  
  if (!id) {
    throw new Error('缺少id参数');
  }
  
  // 数据验证
  validateData(data);
  
  // 更新数据
  const updateData = {
    ...data,
    updated_time: new Date()
  };
  
  await db.collection('your_collection').doc(id).update({
    data: updateData
  });
  
  console.log('[handleUpdate] 更新成功', { id });
  
  return {
    message: '更新成功'
  };
}

/**
 * 处理删除操作(软删除)
 */
async function handleDelete(event) {
  const { id } = event;
  
  if (!id) {
    throw new Error('缺少id参数');
  }
  
  // 软删除:标记为已删除
  await db.collection('your_collection').doc(id).update({
    data: {
      is_deleted: true,
      deleted_time: new Date()
    }
  });
  
  console.log('[handleDelete] 删除成功', { id });
  
  return {
    message: '删除成功'
  };
}

/**
 * 处理查询操作
 */
async function handleQuery(event) {
  const { id } = event;
  
  if (!id) {
    throw new Error('缺少id参数');
  }
  
  const { data } = await db.collection('your_collection')
    .doc(id)
    .get();
  
  if (!data) {
    throw new Error('数据不存在');
  }
  
  console.log('[handleQuery] 查询成功', { id });
  
  return data;
}

/**
 * 处理列表查询
 */
async function handleList(event) {
  const { 
    page = 1, 
    pageSize = 20, 
    filter = {},
    orderBy = 'created_time',
    order = 'desc'
  } = event;
  
  // 构建查询条件
  const where = {
    is_deleted: false,
    ...filter
  };
  
  // 查询总数
  const countResult = await db.collection('your_collection')
    .where(where)
    .count();
  
  // 查询列表
  const { data: list } = await db.collection('your_collection')
    .where(where)
    .orderBy(orderBy, order)
    .skip((page - 1) * pageSize)
    .limit(pageSize)
    .get();
  
  console.log('[handleList] 查询成功', { 
    total: countResult.total,
    page,
    pageSize
  });
  
  return {
    list: list,
    total: countResult.total,
    page: page,
    pageSize: pageSize,
    totalPages: Math.ceil(countResult.total / pageSize)
  };
}

/**
 * 数据验证函数
 */
function validateData(data) {
  if (!data || typeof data !== 'object') {
    throw new Error('无效的数据格式');
  }
  
  // 根据实际业务添加验证逻辑
  // 例如:
  // if (!data.name || data.name.length > 50) {
  //   throw new Error('名称不能为空且长度不能超过50');
  // }
}

2. 云函数配置文件

// cloudfunctions/pet_service_template/config.json
{
  "permissions": {
    "openapi": []
  },
  "timeout": 10,
  "envVariables": {
    "ENV_ID": "{{env.ENV_ID}}"
  }
}
// cloudfunctions/pet_service_template/package.json
{
  "name": "pet_service_template",
  "version": "1.0.0",
  "description": "云函数模板",
  "main": "index.js",
  "dependencies": {
    "wx-server-sdk": "~2.6.3"
  }
}

🛠️ 实战案例:宠物服务云函数

完整的宠物管理云函数

// cloudfunctions/pet_pet_service/index.js
const cloud = require('wx-server-sdk');
cloud.init({ env: cloud.DYNAMIC_CURRENT_ENV });
const db = cloud.database();
const _ = db.command;

exports.main = async (event, context) => {
  console.log('[pet_pet_service] 请求:', event);
  
  try {
    const result = await routeAction(event);
    return { success: true, data: result };
  } catch (error) {
    console.error('[pet_pet_service] 错误:', error);
    return {
      success: false,
      error: error.message,
      code: error.code || 'UNKNOWN_ERROR'
    };
  }
};

async function routeAction(event) {
  const { action } = event;
  
  switch (action) {
    case 'createPet':
      return await createPet(event);
    case 'updatePet':
      return await updatePet(event);
    case 'deletePet':
      return await deletePet(event);
    case 'getPetList':
      return await getPetList(event);
    case 'getPetDetail':
      return await getPetDetail(event);
    default:
      throw { code: 'INVALID_ACTION', message: '未知操作' };
  }
}

// 创建宠物档案
async function createPet(event) {
  const { userId, petData } = event;
  
  // 验证必填字段
  if (!petData.name || !petData.type || !petData.breed) {
    throw { code: 'INVALID_DATA', message: '缺少必填字段' };
  }
  
  // 计算每日热量需求
  const dailyCalories = calculateDailyCalories(petData);
  
  // 创建记录
  const result = await db.collection('pet_pets').add({
    data: {
      user_id: userId,
      name: petData.name,
      type: petData.type,
      breed: petData.breed,
      gender: petData.gender,
      age: petData.age,
      weight: petData.weight,
      health_status: petData.health_status || 'healthy',
      special_needs: petData.special_needs || [],
      activity_level: petData.activity_level,
      daily_calories: dailyCalories,
      created_time: new Date(),
      updated_time: new Date(),
      is_deleted: false
    }
  });
  
  // 更新用户宠物数量
  await db.collection('pet_users').doc(userId).update({
    data: {
      'stats.pet_count': _.inc(1),
      updated_time: new Date()
    }
  });
  
  console.log('[createPet] 创建成功', { petId: result._id });
  
  return {
    petId: result._id,
    message: '宠物档案创建成功'
  };
}

// 获取宠物列表
async function getPetList(event) {
  const { userId } = event;
  
  const { data: petList } = await db.collection('pet_pets')
    .where({
      user_id: userId,
      is_deleted: false
    })
    .orderBy('created_time', 'desc')
    .get();
  
  console.log('[getPetList] 查询成功', { count: petList.length });
  
  return {
    pet_list: petList,
    total: petList.length
  };
}

// 获取宠物详情
async function getPetDetail(event) {
  const { petId } = event;
  
  const { data } = await db.collection('pet_pets').doc(petId).get();
  
  if (!data) {
    throw { code: 'PET_NOT_FOUND', message: '宠物不存在' };
  }
  
  // 获取最近的健康记录
  const { data: recentRecords } = await db.collection('pet_health_records')
    .where({ pet_id: petId })
    .orderBy('record_date', 'desc')
    .limit(5)
    .get();
  
  return {
    ...data,
    recent_health_records: recentRecords
  };
}

// 计算每日热量需求
function calculateDailyCalories(petData) {
  const RER = 70 * Math.pow(petData.weight, 0.75);
  
  let multiplier = 1.6;
  if (petData.age < 1) {
    multiplier = 2.0;
  } else if (petData.age > 7) {
    multiplier = 1.2;
  }
  
  const activityMultiplier = {
    'low': 1.2,
    'medium': 1.5,
    'high': 1.8
  };
  
  return Math.round(RER * multiplier * 
                   (activityMultiplier[petData.activity_level] || 1.5));
}

🚀 云函数部署

1. 手动部署(微信开发者工具)

# 步骤:
1. 在微信开发者工具中打开项目
2. 找到云函数目录
3. 右键点击要部署的云函数文件夹
4. 选择"云函数增量上传"或"云函数全量上传"
5. 等待上传完成

2. 命令行部署

# 安装云开发CLI工具
npm install -g @cloudbase/cli

# 登录
tcb login

# 部署单个云函数
tcb functions:deploy pet_pet_service

# 部署所有云函数
tcb functions:deploy --all

3. 批量部署脚本

#!/bin/bash
# deploy-all-functions.sh

echo "开始部署所有云函数..."

# 定义所有云函数列表
functions=(
  "pet_user_service"
  "pet_pet_service"
  "pet_ai_expert_service"
  "pet_recommendation_service"
  "pet_health_analysis"
)

# 循环部署
for func in "${functions[@]}"; do
  echo "----------------------------------------"
  echo "部署云函数: $func"
  echo "----------------------------------------"
  
  cd "cloudfunctions/$func" || exit
  
  # 安装依赖
  echo "安装依赖..."
  npm install
  
  # 返回根目录
  cd ../..
  
  # 部署云函数
  echo "上传云函数..."
  tcb functions:deploy "$func"
  
  if [ $? -eq 0 ]; then
    echo "✅ $func 部署成功"
  else
    echo "❌ $func 部署失败"
    exit 1
  fi
  
  echo ""
done

echo "========================================="
echo "所有云函数部署完成!"
echo "========================================="

🧪 云函数测试

1. 本地测试

// test/pet_pet_service.test.js
const assert = require('assert');

// 模拟云函数
async function testCreatePet() {
  const event = {
    action: 'createPet',
    userId: 'test_user_123',
    petData: {
      name: '旺财',
      type: 'dog',
      breed: 'golden_retriever',
      gender: 'male',
      age: 2,
      weight: 28.5,
      activity_level: 'high'
    }
  };
  
  // 这里应该调用实际的云函数
  // const result = await cloudFunction(event);
  
  console.log('测试创建宠物档案...');
  // assert.strictEqual(result.success, true);
  console.log('✅ 测试通过');
}

testCreatePet();

2. 云端测试

在微信开发者工具中:

// 工具 -> 云开发 -> 云函数 -> 选择函数 -> 右键测试

// 测试参数
{
  "action": "getPetList",
  "userId": "user_12345678"
}

📊 本课总结

完成本课后,你已经掌握:

  1. ✅ 云函数标准架构设计
  2. ✅ 统一的错误处理机制
  3. ✅ 完整的日志记录方案
  4. ✅ 云函数部署流程
  5. ✅ 测试与调试方法

🎓 下节预告

在第9课中,我们将学习:

  • 微信小程序UI设计规范
  • 组件化开发最佳实践
  • 页面性能优化技巧
  • 用户体验提升方案

Logo

火山引擎开发者社区是火山引擎打造的AI技术生态平台,聚焦Agent与大模型开发,提供豆包系列模型(图像/视频/视觉)、智能分析与会话工具,并配套评测集、动手实验室及行业案例库。社区通过技术沙龙、挑战赛等活动促进开发者成长,新用户可领50万Tokens权益,助力构建智能应用。

更多推荐