You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Node.js中通过Autodesk APS API下载SVF格式模型衍生品

解决方案

修正后的代码实现

const fs = require('fs').promises;
const path = require('path');
const { AuthClientTwoLegged, DerivativesApi } = require('@aps/node');
const crypto = require('crypto');

const CLIENT_ID = process.env.APS_CLIENT_ID;
const CLIENT_SECRET = process.env.APS_CLIENT_SECRET;
const OBJECT_URN = 'your-object-urn'; // Base64编码的URN
const OUTPUT_DIR = './downloads';

// 递归遍历所有衍生文件节点
async function traverseDerivativeNodes(node, derivativesApi, token, baseDir) {
    // 处理当前节点的文件(如果有urn)
    if (node.urn) {
        // 解码URN得到实际文件路径(APS返回的urn是Base64编码的相对路径)
        const decodedUrn = Buffer.from(node.urn, 'base64').toString('utf8');
        const filePath = path.join(baseDir, decodedUrn);
        const fileDir = path.dirname(filePath);

        // 创建目录(如果不存在)
        await fs.mkdir(fileDir, { recursive: true });

        console.log(`Downloading: ${decodedUrn} -> ${filePath}`);

        // 以流的方式下载,避免内存溢出(适合大文件)
        const response = await derivativesApi.getDerivativeManifest(OBJECT_URN, node.urn, {}, {
            authorization: `Bearer ${token.access_token}`,
            responseType: 'stream'
        });

        // 写入文件流
        const writeStream = fs.createWriteStream(filePath);
        await new Promise((resolve, reject) => {
            response.body.pipe(writeStream);
            writeStream.on('finish', resolve);
            writeStream.on('error', reject);
        });

        // 可选:验证文件哈希完整性
        if (node.hashed) {
            const fileBuffer = await fs.readFile(filePath);
            const hash = crypto.createHash('md5').update(fileBuffer).digest('hex');
            if (hash !== node.hashed.toLowerCase()) {
                throw new Error(`File integrity check failed: ${decodedUrn}`);
            }
            console.log(`Integrity check passed: ${decodedUrn}`);
        }
    }

    // 递归处理子节点
    if (node.children && Array.isArray(node.children)) {
        for (const child of node.children) {
            await traverseDerivativeNodes(child, derivativesApi, token, baseDir);
        }
    }
}

async function downloadSVF() {
    // 初始化认证客户端
    const authClient = new AuthClientTwoLegged(CLIENT_ID, CLIENT_SECRET, ['data:read'], true);
    const token = await authClient.authenticate();
    const derivativesApi = new DerivativesApi();

    // 创建输出根目录
    await fs.mkdir(OUTPUT_DIR, { recursive: true });

    // 获取模型清单
    const manifest = await derivativesApi.getManifest(OBJECT_URN, {}, { authorization: `Bearer ${token.access_token}` });
    const derivatives = manifest.body.derivatives;

    // 遍历所有SVF类型的衍生品
    for (const derivative of derivatives) {
        if (derivative.outputType === 'svf') {
            // 递归遍历该衍生品下的所有文件节点
            await traverseDerivativeNodes(derivative, derivativesApi, token, OUTPUT_DIR);
        }
    }

    console.log('All SVF derivatives downloaded successfully!');
}

downloadSVF().catch(console.error);

针对疑问的解答

1. 确保下载所有相关文件

  • 递归遍历节点:SVF衍生品的文件结构是嵌套的(比如.sdb、纹理文件可能在子节点的子节点中),需要递归遍历children层级,而非仅遍历直接子节点。
  • 解码URN路径:API返回的node.urn是Base64编码的相对路径,解码后才能还原原始的目录结构(比如models/0.sdb),避免把完整路径当成单个文件名。
  • 创建目录结构:根据解码后的路径自动创建对应的子目录,确保文件保存到正确的位置。

2. 复现VS Code扩展的下载功能

VS Code的APS扩展没有使用特殊API端点,核心工作流和上述代码一致:

  1. 通过getManifest获取模型的完整衍生清单
  2. 递归遍历清单中所有outputType为svf的节点及其子节点
  3. 对每个节点,调用getDerivativeManifest下载文件,并按原始目录结构保存

3. 大型文件与完整性最佳实践

  • 流式下载:设置responseType: 'stream',用流的方式写入文件,避免将大文件全部加载到内存中导致溢出。
  • 文件哈希验证:每个节点的hashed字段是文件的MD5哈希值,下载后计算本地文件的MD5并对比,确保文件未损坏。
  • 错误重试机制:可以为下载逻辑添加重试逻辑(比如使用p-retry库),处理临时网络错误。
  • 断点续传:对于超大文件,可使用HTTP的Range请求头,只下载未完成的部分(需要记录已下载的字节数)。

内容的提问来源于stack exchange,提问作者Lokeswar Mamallan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 18:35:16