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
相关产品推荐
相关产品推荐

