前端与云服务交互

59 阅读6分钟

前端与云服务交互

在uniCloud开发中,前端与云服务的交互是实现应用功能的关键环节。本文将详细介绍前端如何与uniCloud的云函数、云对象、云数据库和云存储进行交互,帮助开发者构建完整的前后端应用。

1. 前端与云服务交互概述

1.1 交互方式

uniCloud提供了多种前端与云服务交互的方式:

  • 云函数调用:通过uniCloud.callFunction方法调用云函数
  • 云对象调用:通过uniCloud.importObject方法调用云对象
  • 云数据库操作:通过uniCloud.database方法操作云数据库
  • 云存储操作:通过uniCloud.uploadFileuniCloud.downloadFile等方法操作云存储

1.2 交互流程

前端与云服务交互的基本流程如下:

  1. 初始化:前端初始化uniCloud环境
  2. 请求:前端发送请求到云服务
  3. 处理:云服务处理请求并返回结果
  4. 响应:前端接收并处理响应结果

1.3 交互特点

uniCloud前端与云服务交互具有以下特点:

  • 简单易用:提供统一的API,简化交互过程
  • 类型安全:支持TypeScript,提供类型提示和检查
  • 自动处理:自动处理请求和响应的序列化和反序列化
  • 错误处理:提供统一的错误处理机制
  • 权限控制:支持基于用户身份的权限控制

2. 云函数调用

2.1 基本调用

// 调用云函数
uniCloud.callFunction({
  name: 'function-name', // 云函数名称
  data: { // 传递给云函数的参数
    param1: 'value1',
    param2: 'value2'
  },
  success: function(res) { // 成功回调
    console.log(res.result); // 云函数返回的结果
  },
  fail: function(err) { // 失败回调
    console.error(err); // 错误信息
  }
});

2.2 异步调用

// 使用async/await调用云函数
async function callCloudFunction() {
  try {
    const res = await uniCloud.callFunction({
      name: 'function-name',
      data: {
        param1: 'value1',
        param2: 'value2'
      }
    });
    
    console.log(res.result); // 云函数返回的结果
  } catch (err) {
    console.error(err); // 错误信息
  }
}

2.3 带UI交互的调用

// 带UI交互的云函数调用
uni.showLoading({
  title: '加载中...'
});

uniCloud.callFunction({
  name: 'function-name',
  data: {
    param1: 'value1',
    param2: 'value2'
  },
  success: function(res) {
    uni.hideLoading();
    console.log(res.result);
  },
  fail: function(err) {
    uni.hideLoading();
    uni.showToast({
      title: '操作失败',
      icon: 'none'
    });
    console.error(err);
  }
});

2.4 批量调用

// 批量调用云函数
async function batchCallFunctions() {
  try {
    const results = await Promise.all([
      uniCloud.callFunction({
        name: 'function1',
        data: { param1: 'value1' }
      }),
      uniCloud.callFunction({
        name: 'function2',
        data: { param2: 'value2' }
      }),
      uniCloud.callFunction({
        name: 'function3',
        data: { param3: 'value3' }
      })
    ]);
    
    console.log(results); // 所有云函数返回的结果
  } catch (err) {
    console.error(err);
  }
}

3. 云对象调用

3.1 基本调用

// 调用云对象
const userObj = uniCloud.importObject('user');

userObj.getUserInfo({
  userId: 'user-id'
}).then(res => {
  console.log(res); // 云对象返回的结果
}).catch(err => {
  console.error(err); // 错误信息
});

3.2 异步调用

// 使用async/await调用云对象
async function callCloudObject() {
  try {
    const userObj = uniCloud.importObject('user');
    const res = await userObj.getUserInfo({
      userId: 'user-id'
    });
    
    console.log(res); // 云对象返回的结果
  } catch (err) {
    console.error(err); // 错误信息
  }
}

3.3 带UI交互的调用

// 带UI交互的云对象调用
async function callCloudObjectWithUI() {
  uni.showLoading({
    title: '加载中...'
  });
  
  try {
    const userObj = uniCloud.importObject('user');
    const res = await userObj.getUserInfo({
      userId: 'user-id'
    });
    
    uni.hideLoading();
    console.log(res);
  } catch (err) {
    uni.hideLoading();
    uni.showToast({
      title: '获取用户信息失败',
      icon: 'none'
    });
    console.error(err);
  }
}

3.4 调用多个方法

// 调用云对象的多个方法
async function callMultipleMethods() {
  try {
    const userObj = uniCloud.importObject('user');
    
    // 调用多个方法
    const [userInfo, userOrders, userSettings] = await Promise.all([
      userObj.getUserInfo({ userId: 'user-id' }),
      userObj.getUserOrders({ userId: 'user-id' }),
      userObj.getUserSettings({ userId: 'user-id' })
    ]);
    
    console.log(userInfo, userOrders, userSettings);
  } catch (err) {
    console.error(err);
  }
}

4. 云数据库操作

4.1 获取数据库实例

// 获取数据库实例
const db = uniCloud.database();

4.2 添加数据

// 添加单条数据
db.collection('collection-name').add({
  field1: 'value1',
  field2: 'value2',
  createTime: Date.now()
}).then(res => {
  console.log(res.id); // 新增数据的ID
}).catch(err => {
  console.error(err);
});

// 添加多条数据
db.collection('collection-name').add([
  {
    field1: 'value1',
    field2: 'value2',
    createTime: Date.now()
  },
  {
    field1: 'value3',
    field2: 'value4',
    createTime: Date.now()
  }
]).then(res => {
  console.log(res.ids); // 新增数据的ID数组
}).catch(err => {
  console.error(err);
});

4.3 查询数据

// 查询单条数据
db.collection('collection-name').doc('document-id').get().then(res => {
  console.log(res.data); // 查询结果
}).catch(err => {
  console.error(err);
});

// 查询多条数据
db.collection('collection-name')
  .where({
    field1: 'value1',
    field2: db.command.gt(100)
  })
  .field({
    field1: true,
    field2: true
  })
  .orderBy('field2', 'desc')
  .skip(0)
  .limit(10)
  .get()
  .then(res => {
    console.log(res.data); // 查询结果
  })
  .catch(err => {
    console.error(err);
  });

4.4 更新数据

// 更新单条数据
db.collection('collection-name').doc('document-id').update({
  field1: 'new-value',
  updateTime: Date.now()
}).then(res => {
  console.log(res.updated); // 更新的数据数量
}).catch(err => {
  console.error(err);
});

// 更新多条数据
db.collection('collection-name')
  .where({
    field1: 'value1'
  })
  .update({
    field2: 'new-value',
    updateTime: Date.now()
  })
  .then(res => {
    console.log(res.updated); // 更新的数据数量
  })
  .catch(err => {
    console.error(err);
  });

4.5 删除数据

// 删除单条数据
db.collection('collection-name').doc('document-id').remove().then(res => {
  console.log(res.deleted); // 删除的数据数量
}).catch(err => {
  console.error(err);
});

// 删除多条数据
db.collection('collection-name')
  .where({
    field1: 'value1'
  })
  .remove()
  .then(res => {
    console.log(res.deleted); // 删除的数据数量
  })
  .catch(err => {
    console.error(err);
  });

4.6 聚合操作

// 聚合操作
db.collection('collection-name')
  .aggregate()
  .match({
    field1: 'value1'
  })
  .group({
    _id: '$field2',
    count: db.command.aggregate.count(),
    sum: db.command.aggregate.sum('$field3')
  })
  .sort({
    count: -1
  })
  .limit(10)
  .end()
  .then(res => {
    console.log(res.data); // 聚合结果
  })
  .catch(err => {
    console.error(err);
  });

5. 云存储操作

5.1 上传文件

// 上传单个文件
uni.chooseImage({
  count: 1,
  success: function(res) {
    const tempFilePath = res.tempFilePaths[0];
    
    uniCloud.uploadFile({
      filePath: tempFilePath,
      cloudPath: 'folder/file-name.jpg',
      onUploadProgress: function(progressEvent) {
        console.log(progressEvent); // 上传进度
      },
      success: function(res) {
        console.log(res.fileID); // 文件ID
      },
      fail: function(err) {
        console.error(err);
      }
    });
  }
});

// 上传多个文件
uni.chooseImage({
  count: 9,
  success: function(res) {
    const tempFilePaths = res.tempFilePaths;
    const fileList = tempFilePaths.map((filePath, index) => {
      return {
        filePath: filePath,
        cloudPath: `folder/file-name-${index}.jpg`
      };
    });
    
    uniCloud.uploadFile({
      fileList: fileList,
      onUploadProgress: function(progressEvent) {
        console.log(progressEvent); // 上传进度
      },
      success: function(res) {
        console.log(res.fileList); // 文件ID列表
      },
      fail: function(err) {
        console.error(err);
      }
    });
  }
});

5.2 下载文件

// 下载单个文件
uniCloud.downloadFile({
  fileID: 'cloud://space-id.folder/file-name.jpg',
  onDownloadProgress: function(progressEvent) {
    console.log(progressEvent); // 下载进度
  },
  success: function(res) {
    console.log(res.tempFilePath); // 临时文件路径
  },
  fail: function(err) {
    console.error(err);
  }
});

// 下载多个文件
uniCloud.downloadFile({
  fileList: [
    'cloud://space-id.folder/file-name-1.jpg',
    'cloud://space-id.folder/file-name-2.jpg'
  ],
  onDownloadProgress: function(progressEvent) {
    console.log(progressEvent); // 下载进度
  },
  success: function(res) {
    console.log(res.fileList); // 临时文件路径列表
  },
  fail: function(err) {
    console.error(err);
  }
});

5.3 删除文件

// 删除单个文件
uniCloud.deleteFile({
  fileList: ['cloud://space-id.folder/file-name.jpg'],
  success: function(res) {
    console.log(res.fileList); // 删除成功的文件ID列表
  },
  fail: function(err) {
    console.error(err);
  }
});

// 删除多个文件
uniCloud.deleteFile({
  fileList: [
    'cloud://space-id.folder/file-name-1.jpg',
    'cloud://space-id.folder/file-name-2.jpg'
  ],
  success: function(res) {
    console.log(res.fileList); // 删除成功的文件ID列表
  },
  fail: function(err) {
    console.error(err);
  }
});

5.4 获取文件信息

// 获取文件信息
uniCloud.getTempFileURL({
  fileList: ['cloud://space-id.folder/file-name.jpg'],
  success: function(res) {
    console.log(res.fileList); // 文件信息列表,包含临时访问链接
  },
  fail: function(err) {
    console.error(err);
  }
});

6. 前端与云服务交互的最佳实践

6.1 错误处理

// 统一的错误处理
function handleError(err) {
  console.error(err);
  
  // 根据错误类型显示不同的提示
  if (err.code === 'TOKEN_EXPIRED') {
    uni.showToast({
      title: '登录已过期,请重新登录',
      icon: 'none'
    });
    // 跳转到登录页
    uni.navigateTo({
      url: '/pages/login/login'
    });
  } else if (err.code === 'PERMISSION_DENIED') {
    uni.showToast({
      title: '没有权限执行此操作',
      icon: 'none'
    });
  } else {
    uni.showToast({
      title: '操作失败,请稍后重试',
      icon: 'none'
    });
  }
}

// 使用统一的错误处理
async function callCloudFunction() {
  try {
    const res = await uniCloud.callFunction({
      name: 'function-name',
      data: {
        param1: 'value1'
      }
    });
    
    console.log(res.result);
  } catch (err) {
    handleError(err);
  }
}

6.2 请求封装

// 封装云函数调用
function callFunction(name, data = {}) {
  return new Promise((resolve, reject) => {
    uniCloud.callFunction({
      name: name,
      data: data,
      success: function(res) {
        resolve(res.result);
      },
      fail: function(err) {
        reject(err);
      }
    });
  });
}

// 使用封装的云函数调用
async function getUserInfo(userId) {
  try {
    const result = await callFunction('getUserInfo', { userId });
    return result;
  } catch (err) {
    handleError(err);
    return null;
  }
}

6.3 数据缓存

// 数据缓存
const cache = {
  data: {},
  timeout: 5 * 60 * 1000, // 缓存过期时间,默认5分钟
  
  // 设置缓存
  set(key, value, timeout = this.timeout) {
    this.data[key] = {
      value: value,
      expire: Date.now() + timeout
    };
  },
  
  // 获取缓存
  get(key) {
    if (!this.data[key]) {
      return null;
    }
    
    if (Date.now() > this.data[key].expire) {
      delete this.data[key];
      return null;
    }
    
    return this.data[key].value;
  },
  
  // 清除缓存
  clear(key) {
    if (key) {
      delete this.data[key];
    } else {
      this.data = {};
    }
  }
};

// 使用缓存
async function getUserInfoWithCache(userId) {
  const cacheKey = `user_${userId}`;
  const cachedData = cache.get(cacheKey);
  
  if (cachedData) {
    return cachedData;
  }
  
  try {
    const result = await callFunction('getUserInfo', { userId });
    cache.set(cacheKey, result);
    return result;
  } catch (err) {
    handleError(err);
    return null;
  }
}

6.4 请求队列

// 请求队列
class RequestQueue {
  constructor() {
    this.queue = [];
    this.running = false;
  }
  
  // 添加请求
  add(request) {
    return new Promise((resolve, reject) => {
      this.queue.push({
        request,
        resolve,
        reject
      });
      
      this.run();
    });
  }
  
  // 执行请求
  async run() {
    if (this.running || this.queue.length === 0) {
      return;
    }
    
    this.running = true;
    
    while (this.queue.length > 0) {
      const { request, resolve, reject } = this.queue.shift();
      
      try {
        const result = await request();
        resolve(result);
      } catch (err) {
        reject(err);
      }
    }
    
    this.running = false;
  }
}

// 创建请求队列
const requestQueue = new RequestQueue();

// 使用请求队列
function callFunctionWithQueue(name, data = {}) {
  return requestQueue.add(() => {
    return callFunction(name, data);
  });
}

6.5 请求重试

// 请求重试
async function callFunctionWithRetry(name, data = {}, maxRetries = 3) {
  let retries = 0;
  
  while (retries < maxRetries) {
    try {
      return await callFunction(name, data);
    } catch (err) {
      retries++;
      
      if (retries === maxRetries) {
        throw err;
      }
      
      // 等待一段时间后重试
      await new Promise(resolve => setTimeout(resolve, 1000 * retries));
    }
  }
}

7. 前端与云服务交互的常见问题

7.1 跨域问题

uniCloud前端与云服务交互不存在跨域问题,因为uniCloud已经处理了跨域请求。

7.2 网络问题

// 处理网络问题
async function callFunctionWithNetworkCheck(name, data = {}) {
  // 检查网络状态
  const networkType = await new Promise(resolve => {
    uni.getNetworkType({
      success: function(res) {
        resolve(res.networkType);
      },
      fail: function() {
        resolve('unknown');
      }
    });
  });
  
  if (networkType === 'none') {
    uni.showToast({
      title: '网络连接不可用,请检查网络设置',
      icon: 'none'
    });
    return null;
  }
  
  try {
    return await callFunction(name, data);
  } catch (err) {
    if (err.code === 'NETWORK_ERROR') {
      uni.showToast({
        title: '网络请求失败,请稍后重试',
        icon: 'none'
      });
    } else {
      handleError(err);
    }
    return null;
  }
}

7.3 超时问题

// 处理超时问题
function callFunctionWithTimeout(name, data = {}, timeout = 10000) {
  return new Promise((resolve, reject) => {
    const timeoutId = setTimeout(() => {
      reject(new Error('请求超时'));
    }, timeout);
    
    uniCloud.callFunction({
      name: name,
      data: data,
      success: function(res) {
        clearTimeout(timeoutId);
        resolve(res.result);
      },
      fail: function(err) {
        clearTimeout(timeoutId);
        reject(err);
      }
    });
  });
}

7.4 并发问题

// 处理并发问题
const requestMap = new Map();

function callFunctionWithConcurrencyControl(name, data = {}, key = null) {
  // 如果没有提供key,则使用name和data的组合作为key
  if (!key) {
    key = `${name}_${JSON.stringify(data)}`;
  }
  
  // 如果已经有相同的请求在进行中,则返回该请求的Promise
  if (requestMap.has(key)) {
    return requestMap.get(key);
  }
  
  // 创建新的请求
  const promise = callFunction(name, data).finally(() => {
    // 请求完成后,从Map中移除
    requestMap.delete(key);
  });
  
  // 将请求添加到Map中
  requestMap.set(key, promise);
  
  return promise;
}

8. 总结

前端与云服务交互是uniCloud应用开发的核心环节,通过本文的介绍,您应该已经了解了前端如何与uniCloud的云函数、云对象、云数据库和云存储进行交互。在实际开发中,根据业务需求,合理使用这些交互方式,可以构建高效、可靠的前后端应用。

同时,本文还提供了一些最佳实践和常见问题的解决方案,可以帮助您更好地处理前端与云服务交互中的各种情况。希望这些内容对您的uniCloud开发有所帮助。