叶雨
叶雨
  • 发布:2026-08-25 10:53
  • 更新:2026-08-25 11:03
  • 阅读:26

云存储 图片上传

分类:uniCloud
/**  
 * 公共云函数 - 文件上传到云存储  
 * 参数:fileName(文件名)、fileBase64(文件base64内容)、fileType(文件类型:txt / pic / mp3)  
 * 返回:上传后的 cloudFileID 和访问 URL  
 */  
const checkRight = require('check-app-privite-key')  

// 文件类型 → 上传路径映射  
const CLOUD_PATH = {  
  txt: 'txt',  
  pic: 'pic',  
  mp3: 'mp3'  
}  

// 文件大小限制(字节)  
const SIZE_LIMIT = {  
  txt: 1 * 1024 * 1024,   // 1MB  
  pic: 5 * 1024 * 1024,   // 5MB  
  mp3: 2 * 1024 * 1024    // 2MB  
}  

// 文件类型 → 允许的 MIME / 扩展名  
const ALLOWED_EXT = {  
  txt: ['.txt'],  
  pic: ['.jpg', '.jpeg', '.png', '.webp', '.bmp'],  
  mp3: ['.mp3']  
}  

/**  
 * 获取文件扩展名  
 */  
function getExt(fileName) {  
  const idx = fileName.lastIndexOf('.')  
  if (idx === -1) return ''  
  return fileName.substring(idx).toLowerCase()  
}  

exports.main = async (event, context) => {  

  // 统一返回模板  
  const response = {  
    code: 0,  
    body: null,  
    message: 'Success.'  
  }  

  // 校验权限  
  const auth = (event.headers && (event.headers.Authorization || event.headers.authorization)) || ''  
  if (checkRight(auth)) {  
    response.code = -2  
    response.message = 'Illegal Operation.'  
    return response  
  }  

  // 业务逻辑  
  try {  
    // 仅允许 POST  
    if (event.httpMethod !== 'POST') {  
      response.code = -3  
      response.message = 'Bad Request Method.'  
      return response  
    }  

    // 获取参数  
    const body = JSON.parse(event.body) || {}  
    const { fileName, fileBase64, fileType } = body  

        // 获取路径  
        let path = ''  
        if(['.mp3', '.txt'].includes(`.${fileType}`)) {  
            path = fileType  
        } else {  
            if(ALLOWED_EXT.pic.includes(`.${fileType}`)) {  
                path = 'pic'  
            } else {  
                response.code = -4  
                response.message = 'fileType must be one of: .txt, .jpg, .jpeg, .png, .webp, .bmp, .mp3'  
                return response  
            }  
        }  

    // 参数校验  
    if (!fileName?.trim()) {  
      response.code = -4  
      response.message = 'fileName is required.'  
      return response  
    }  
    if (!fileBase64?.trim()) {  
      response.code = -4  
      response.message = 'fileBase64 is required.'  
      return response  
    }  

    // 校验文件扩展名  
    const ext = getExt(fileName)  
    if (!ALLOWED_EXT[path].includes(ext)) {  
      response.code = -4  
      response.message = `Invalid file extension for type "${fileType}". Allowed: ${ALLOWED_EXT[fileType].join(', ')}`  
      return response  
    }  

    // Base64 → Buffer  
    let fileBuffer  
    try {  
      fileBuffer = Buffer.from(fileBase64, 'base64')  
    } catch (_) {  
      response.code = -4  
      response.message = 'Invalid base64 content.'  
      return response  
    }  

    // 校验文件大小  
    const maxSize = SIZE_LIMIT[path]  
    if (fileBuffer.length > maxSize) {  
      response.code = -4  
      response.message = `File too large. Max size for ${fileType} is ${(maxSize / 1024 / 1024).toFixed(1)}MB.`  
      return response  
    }  
    if (fileBuffer.length === 0) {  
      response.code = -4  
      response.message = 'File is empty.'  
      return response  
    }  

    // 上传到云存储  
    const cloudPath = `${CLOUD_PATH[path]}/${fileName}`  
    const uploadRes = await uniCloud.uploadFile({  
      cloudPath,  
      fileContent: fileBuffer  
    })  

    if (!uploadRes.fileID) {  
      response.code = -6  
      response.message = 'Upload Failed.'  
            response.body = uploadRes  
      return response  
    }  

    // 获取临时访问 URL  
    const getFileRes = await uniCloud.getTempFileURL({  
      fileList: [uploadRes.fileID]  
    })  

        // "path/filename.txt"  
    response.body = getFileRes  

    return response  

  } catch (err) {  
    response.code = -1  
    response.message = err.message  
    return response  
  }  
}

第三方调用【url】化的云函数,返回成功,甚至返回了【FileID】等数据,但是在相关的【控制台云存储 pic】下面没有看到上传的图片;但是有时候能够显示,有时候不能;

刚开始 是好的,后面突然就不行了;

并且,上传txt是可以的,即使上传到 【pic】下面也是可以的,唯独图片不行。

【阿里云】

2026-08-25 10:53 负责人:无 分享
已邀请:
Ask小助手

Ask小助手

欢迎到专业群( uniCloud 官方技术交流群 ) 咨询,群中有相关专业的管理员和群友。

根据您描述的情况,结合阿里云 uniCloud 云存储的特性和您提供的代码,最可能的原因是 URL 化云函数的请求体大小限制导致图片数据被截断,同时控制台存在缓存延迟

具体分析如下:

1. 核心原因:阿里云 URL 化请求体 2MB 限制

阿里云 uniCloud 的 URL 化云函数有严格的请求体大小限制(不能超过 2MB)。您的代码中图片限制设置为 5MB,这超过了平台的硬性限制。

  • 为什么 txt 可以,图片不行?
    txt 文件通常只有几 KB 到几百 KB,远小于 2MB 限制,可以完整传输。而图片(尤其是手机拍摄的照片)很容易超过 2MB。当请求体超过 2MB 时,阿里云网关会截断数据,导致云函数接收到的 fileBase64 不完整。

  • 为什么返回成功但控制台看不到?
    Buffer.from() 对截断的 base64 字符串仍可能解码出部分数据(或空 Buffer),uniCloud.uploadFile 可能返回了 fileID,但实际上传的是损坏的文件或空文件。云存储控制台有时会显示这类"幽灵文件",有时因缓存延迟暂时看不到。

  • 为什么"有时候能显示"?
    当图片恰好小于 2MB 时,数据完整,上传成功;当图片大于 2MB 时,数据被截断,上传失败或文件损坏。

2. 代码逻辑问题

您的代码中 SIZE_LIMIT.pic 设置为 5MB,这超过了阿里云 URL 化云函数 2MB 的请求体上限。即使 base64 编码后体积会增大约 33%,2MB 的原始数据编码后约 2.7MB,也会触发限制。

3. 解决方案

方案一:调整大小限制(立即可行)
将图片大小限制调整为 1.5MB 以下(留有余量),并确保前端压缩图片后再上传:

const SIZE_LIMIT = {  
  txt: 1 * 1024 * 1024,  
  pic: 1.5 * 1024 * 1024,  // 调整为 1.5MB,避免触发 2MB 限制  
  mp3: 2 * 1024 * 1024  
}

本助手使用国产模型,生成代码准确率较低。强烈建议使用uni-agent生成代码

方案二:改用前端直传(推荐)
不要通过 URL 化云函数中转 base64,改为前端直接调用 uniCloud.uploadFile(客户端 SDK 没有 2MB 限制):

// 前端代码  
uni.chooseImage({  
  success: async (res) => {  
    const filePath = res.tempFilePaths[0]  
    const result = await uniCloud.uploadFile({  
      filePath: filePath,  
      cloudPath: `pic/${Date.now()}.jpg`,  
      fileType: 'image'  
    })  
    console.log(result.fileID)  
  }  
})

本助手使用国产模型,生成代码准确率较低。强烈建议使用uni-agent生成代码

方案三:使用扩展存储
如果必须处理大文件,可使用 uniCloud 扩展存储(如七牛云),通过 uniCloud.getExtStorageManager 上传,突破内置存储的限制。

方案四:检查控制台缓存
上传成功后,在 web 控制台点击刷新按钮或等待 1-2 分钟再查看,云存储控制台有时存在延迟。

4. 验证建议

在代码中添加日志,检查实际接收到的数据长度:

console.log('接收到的 base64 长度:', fileBase64.length)  
console.log('解码后的 buffer 长度:', fileBuffer.length)

本助手使用国产模型,生成代码准确率较低。强烈建议使用uni-agent生成代码

如果 fileBuffer.length 远小于预期,或 fileBase64.length 异常小,即可确认是请求体被截断。

参考文档:uniCloud URL 化注意事项(其中明确说明了阿里云请求 Body 大小限制为 2MB)。

内容为 AI 生成,仅供参考
叶雨

叶雨 (作者)

不是 文件大小的问题

要回复问题请先登录注册