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

Next JS+Sanity:从Blocks数组动态获取文件URL遇undefined问题

解决Sanity buildFileUrl生成undefined URL的问题

问题根源

你遇到的undefined.undefined URL问题,本质是传入buildFileUrl的sanityFile.asset只是资产引用(仅含_ref字段),而非完整的Sanity资产文档。buildFileUrl需要资产文档中的_id、extension等核心字段才能生成有效URL,缺少这些字段就会出现占位符undefined。

解决方案

1. 确保GROQ查询展开资产引用

在获取包含视频文件的Portable Text数据时,必须在GROQ查询中用->操作符展开asset引用,才能拿到完整的资产元数据:

*[_type == "yourDocumentType"] {
  // 其他字段...
  body[] {
    _type,
    // 针对自定义视频块类型(比如"video")展开asset
    _type == "video" => {
      file {
        asset-> // 关键:展开asset引用,获取完整资产数据
      }
    },
    // 其他block类型处理...
  }
}

如果视频字段直接存在于文档而非Portable Text里,查询同样要展开:

*[_type == "yourDocumentType"] {
  videoFile {
    asset->
  }
}

2. 验证asset对象结构

调用getSanityFileUrl前,先打印sanityFile.asset确认字段完整性:

export function getSanityFileUrl(sanityFile) {
  console.log('Sanity Asset:', sanityFile.asset);
  // 确认输出包含_id、extension、originalFilename等字段
  const fileUrl = buildFileUrl(sanityFile.asset, {
    projectId: sanityConfig.projectId,
    dataset: sanityConfig.dataset
  });
  console.log(fileUrl);
  return fileUrl;
}

如果打印结果只有_ref字段,说明查询未展开引用,回到步骤1修正GROQ。

3. 自定义Portable Text视频组件(适配@portabletext/react)

在解析Blocks数组时,给视频类型的block配置自定义组件,确保URL生成逻辑正确:

import { PortableText } from '@portabletext/react';
import { getSanityFileUrl } from './your-utils-file';

const components = {
  types: {
    // 假设你的Portable Text视频块_type为"video"
    video: ({ value }) => {
      const videoUrl = getSanityFileUrl(value.file);
      return videoUrl ? (
        <video controls src={videoUrl}>
          <p>你的浏览器不支持视频播放</p>
        </video>
      ) : null;
    },
    // 其他block类型组件...
  }
};

// 在页面组件中使用
<PortableText value={yourDocument.body} components={components} />

4. 备选:手动构造URL(若buildFileUrl仍异常)

如果buildFileUrl还是无法生成有效URL,可以通过asset的_id手动拼接(前提是asset已展开,能拿到_id):

export function getSanityFileUrl(sanityFile) {
  if (!sanityFile.asset?._id) return null;
  // 从_id中拆分出资产ID和扩展名(格式:asset-<uuid>-<extension>)
  const [, assetId, extension] = sanityFile.asset._id.split('-');
  return `https://cdn.sanity.io/files/${sanityConfig.projectId}/${sanityConfig.dataset}/${assetId}.${extension}`;
}

内容的提问来源于stack exchange,提问作者James Hubert

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 17:31:57