f***@tmp.dcloud.io
f***@tmp.dcloud.io
  • 发布:2026-07-19 22:15
  • 更新:2026-07-19 22:17
  • 阅读:55

【报Bug】【阿里云 uniCloud 内置存储】服务空间切为私有后,云函数 getTempFileURL 返回地址不可访问

分类:uniCloud

产品分类: uniCloud/App

示例代码:
'use strict'  

const http = require('http')  
const https = require('https')  

function text(value) {  
  return String(value == null ? '' : value).trim()  
}  

function requestUrl(input, timeoutMs = 8000) {  
  const urlText = text(input)  
  return new Promise((resolve) => {  
    let settled = false  
    const finish = (value) => {  
      if (settled) return  
      settled = true  
      resolve(value)  
    }  

    try {  
      const parsed = new URL(urlText)  
      const client = parsed.protocol === 'http:'  
        ? http  
        : parsed.protocol === 'https:'  
          ? https  
          : null  

      if (!client) {  
        finish({  
          protocol: 'unsupported',  
          hasQuery: parsed.search.length > 0,  
          reachedServer: false,  
          statusClass: 0,  
          reachable: false  
        })  
        return  
      }  

      const req = client.get(parsed, (res) => {  
        const statusCode = Number(res.statusCode || 0)  
        res.resume()  
        res.on('end', () => finish({  
          protocol: parsed.protocol.slice(0, -1),  
          hasQuery: parsed.search.length > 0,  
          reachedServer: true,  
          statusClass: statusCode ? Math.floor(statusCode / 100) : 0,  
          reachable: statusCode >= 200 && statusCode < 400  
        }))  
      })  

      req.on('error', () => finish({  
        protocol: parsed.protocol.slice(0, -1),  
        hasQuery: parsed.search.length > 0,  
        reachedServer: false,  
        statusClass: 0,  
        reachable: false  
      }))  
      req.setTimeout(timeoutMs, () => {  
        req.destroy()  
        finish({  
          protocol: parsed.protocol.slice(0, -1),  
          hasQuery: parsed.search.length > 0,  
          reachedServer: false,  
          statusClass: 0,  
          reachable: false  
        })  
      })  
    } catch (_) {  
      finish({  
        protocol: 'invalid',  
        hasQuery: false,  
        reachedServer: false,  
        statusClass: 0,  
        reachable: false  
      })  
    }  
  })  
}  

exports.main = async () => {  
  const fileContent = Buffer.from(  
    'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mP8/x8AAusB9Y9ZQmcAAAAASUVORK5CYII=',  
    'base64'  
  )  
  const suffix = `${Date.now()}-${Math.random().toString(36).slice(2, 10)}`  
  let fileId = ''  

  try {  
    const uploaded = await uniCloud.uploadFile({  
      cloudPath: `probe/private/${suffix}.png`,  
      cloudPathAsRealPath: true,  
      fileContent  
    })  
    fileId = text(uploaded && (uploaded.fileID || uploaded.fileId || uploaded.url))  
    if (!fileId) throw new Error('UPLOAD_FILE_ID_EMPTY')  

    const temporary = await uniCloud.getTempFileURL({ fileList: [fileId] })  
    const firstItem = temporary  
      && Array.isArray(temporary.fileList)  
      && temporary.fileList[0]  
    const tempFileURL = text(firstItem && (  
      firstItem.tempFileURL  
      || firstItem.tempFileUrl  
      || firstItem.url  
    ))  
    if (!tempFileURL) throw new Error('TEMP_FILE_URL_EMPTY')  

    const probe = await requestUrl(tempFileURL)  
    return {  
      hasTempFileURL: true,  
      sameAsRawFileId: tempFileURL === fileId,  
      protocol: probe.protocol,  
      hasQuery: probe.hasQuery,  
      reachedServer: probe.reachedServer,  
      statusClass: probe.statusClass,  
      reachable: probe.reachable  
    }  
  } finally {  
    if (fileId) {  
      await uniCloud.deleteFile({ fileList: [fileId] })  
    }  
  }  
}

操作步骤:
  1. 在阿里云 uniCloud 隔离服务空间把内置存储整体权限设置为“私有”。
  2. 临时地址有效期设置为 600 秒。
  3. 上传并运行下方最小复现云函数,运行时使用 Node.js 16。
  4. 云函数上传一个虚构的 1×1 PNG 文件,取得 uploadFile 返回的 fileID。
  5. 在同一云函数调用 uniCloud.getTempFileURL({ fileList: [fileID] })。
  6. 仅判断临时地址是否非空、是否与原地址相同、协议、是否有查询参数、是否到达服务器、HTTP 状态类别和是否可访问,不输出真实地址或鉴权内容。
  7. 无论成功或失败,均删除虚构测试文件。

预期结果:

私有模式下原始地址不能匿名访问;云函数调用 uniCloud.getTempFileURL 后,应取得在 600 秒有效期内可访问该私有文件的临时地址;删除文件后原地址和临时地址均不能继续访问。

实际结果:

原始地址匿名访问被拒绝;getTempFileURL 返回 tempFileURL 非空,但两次独立取址均不能访问私有文件。脱敏诊断在确认请求已到达服务器后得到“地址无查询参数”,固定阶段码为 P2_HOUSE_STORAGE_TEMP_ACCESS_UNPROVEN、P2_HOUSE_STORAGE_TEMP_NO_AUTH_QUERY。重新上传未修改云函数后结果不变。每次清理均成功,后置残留为 0。

bug描述:

问题发生在阿里云 uniCloud 内置存储,仅在隔离测试空间复现,未操作正式环境。

环境:

  • HBuilderX 5.15.2026070915 正式版
  • macOS 26.5.2
  • 阿里云 uniCloud 内置存储
  • 云函数 Node.js 16,512 MB / 45 秒
  • 存储整体权限:私有
  • 临时地址有效期:600 秒
  • uploadFile 参数:cloudPathAsRealPath: true

现象:

  1. 公有模式下原始地址可以匿名访问。
  2. 切换为私有后,原始地址匿名访问被拒绝,说明私有配置至少部分生效。
  3. 同一云函数两次调用 uniCloud.getTempFileURL,均取得非空 tempFileURL,但两个地址均不能访问私有文件。
  4. 脱敏诊断确认请求已到达服务器,返回地址没有查询参数,访问仍失败。没有查询参数本身不能单独证明完全没有鉴权,烦请确认平台实际签名机制。
  5. 按已有官方问答建议重新上传未修改云函数后,结果不变。
  6. 每次测试文件和数据库夹具均清理成功,后置残留为 0。

安全影响:当前无法证明敏感证据文件可被授权角色临时访问,因此不能用于联系人、授权截图、身份证明等私密资料,也不会采用改回公有存储作为替代方案。

希望确认:

  1. URL 形态 fileID 是否应返回可访问私有文件的临时地址;
  2. 当前鉴权形式是查询参数、路径签名、跳转还是其他机制;
  3. 是否仍存在云端返回未签名或不可用地址的兼容问题;
  4. 是否与 Node.js 16 或既有部署链路有关;
  5. 服务空间是否还需额外刷新或迁移;
  6. 官方“阿里云已支持权限控制”和“阿里云内置存储不支持私有存储”两份文档应以哪一项为准。
2026-07-19 22:15 负责人:无 分享
已邀请:
Ask小助手

Ask小助手 - Ask社区AI助手

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

感谢您提交详尽的 Bug 反馈。从反馈内容来看,问题描述清晰、逻辑严密,复现步骤和代码示例完整,体现了极高的专业素养。以下是对该反馈的评审与技术分析:

1. Bug 反馈内容评审

  • BUG 描述:非常详细。您准确列出了 HBuilderX 版本、系统环境、云厂商、运行时及存储权限配置,并客观描述了测试现象与安全影响,提出的 6 个确认点也直击问题核心,便于官方人员快速理解上下文。
  • 代码示例:完整且可直接运行。代码实现了文件上传、获取临时链接、探测 HTTP 可达性及清理测试夹具的完整闭环,且对输出进行了脱敏处理,官方无需二次调整即可直接部署复现。
  • 复现步骤:描述清晰。结合提供的代码示例,官方人员可以按图索骥在隔离服务空间内完成复现。
  • 预期与实际结果:预期合理,符合私有存储的安全模型;实际结果的记录客观详实,记录了阶段码与诊断细节,排除了主观臆断。
  • 分类信息:完整。

2. Bug 是否成立分析

结合知识库与官方文档记录,该 Bug 反馈成立且定位准确

关于您提出的确认点,分析如下:

  1. URL 形态与临时地址:在私有权限下,getTempFileURL 理应返回带鉴权参数(如查询参数或签名)的临时可访问地址。若返回无鉴权参数的裸链接,则必然无法访问私有文件。
  2. 鉴权机制:阿里云 OSS 私有文件的临时访问通常依赖 URL 查询参数(如 ExpiresOSSAccessKeyIdSignature)进行鉴权。您观测到“地址无查询参数”,说明云端未正确下发签名。
  3. 兼容与文档冲突问题:您的怀疑非常精准。根据官方文档 getTempFileURL 记载,阿里云云存储自 HBuilderX 4.76 版本起才正式支持权限控制。而在早期版本中,官方明确说明“阿里云的云存储不支持权限控制”,getTempFileURL 仅为抹平接口差异而保留,返回的是原链接。您当前使用的 HBuilderX 5.15 理论上已包含该能力,但若在此版本下仍返回无签名的原链接,说明平台在底层链路或该版本的实现上存在兼容性缺陷或回归问题。因此,应以“阿里云已支持权限控制(4.76+)”的文档为准,并判定当前环境存在 Bug。

3. 替代方案与建议

由于该 Bug 导致私有文件无法正常授权访问,若您的业务急需上线敏感资料(如身份证明、授权截图)的访问能力,建议暂时采用以下替代方案:

  • 方案一:使用扩展存储
    DCloud 联合主流 CDN 厂商单独提供了 uniCloud 扩展存储,具备更强大的自定义权限控制,且不受阿里云内置存储底层限制。详情请参考:uniCloud 扩展存储文档

  • 方案二:使用支付宝云或腾讯云
    若业务允许多云切换,支付宝云与腾讯云的内置存储原生支持完善的私有权限与临时 URL 机制。根据社区官方回复,支付宝云私有权限的临时 URL 默认有效期为 1 小时。

  • 方案三:云函数中转下载
    在云函数内通过 uniCloud.downloadFile 获取文件 Buffer,手动设置响应头(如 Content-Disposition)并透传给客户端。此方案会消耗云函数运行时长与内存,不适合大文件,仅适用于小体积图片或证件。

您的反馈对平台改进非常有价值,建议持续关注官方后续版本的修复公告。

内容为 AI 生成,仅供参考

要回复问题请先登录注册