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

Next.js 13动态路由服务组件Sanity数据获取失败

Next.js 13 Server Component 无法从 Sanity 获取动态路由数据问题

我在使用 Next.js 13 开发网站时,尝试在动态路由的 Server Component 中通过 Sanity Client 获取指定项目数据,但始终返回空结果。控制台日志显示查询语句格式正确,但就是拿不到数据。


相关代码

动态路由页面代码

import React from 'react'
import { client } from '@/lib/sanityClient';

export default async function Page({params}) {
  const query = `*[type == "project" && _id == "${params.id}"]`;

  const project = await client.fetch(query , { cache: 'force-cache' });
  
  console.log(query);
  console.log(project)

  return (
    <div>
      <h1> Dummy static text</h1>
      <h1>{project.name}</h1>
      <p>{project.description}</p>
    </div>
  )
}

Sanity Schema 定义

export default {
    name: 'project',
    title: 'Project',
    type: 'document',
    fields: [
      {
        name: 'name',
        title: 'Name',
        type: 'string',
        validation: (Rule) => Rule.required().max(100),
      },
      {
        name: 'description',
        title: 'Description',
        type: 'text',
        validation: (Rule) => Rule.required().max(500),
      },
      {
        name: 'images',
        title: 'Images',
        type: 'array',
        of: [
          {
            type: 'image',
            options: {
              hotspot: true,
            },
          },
        ],
        validation: (Rule) => Rule.required().min(1),
      },
    ],
  };

Sanity Client 配置

import { createClient } from "next-sanity";
import imageUrlBuilder from '@sanity/image-url';

export const client = createClient({
    projectId: "7guc57bn",
    dataset: "production",
    apiVersion: "2022-03-25",
    token: process.env.NEXT_PUBLIC_SANITY_API_TOKEN,
    useCdn: true
  });
  
const builder = imageUrlBuilder(client);

export const urlFor = (source) => builder.image(source);

问题排查与修复方案

1. 查询结果是数组而非单个对象

Sanity 的 GROQ 查询 *[...] 返回的是数组,哪怕只有一条匹配结果。直接用 project.name 会报错,因为数组没有 name 属性。

修复方式二选一:

// 方案1:从数组中取第一个元素
const project = (await client.fetch(query, { cache: 'force-cache' }))[0];

// 方案2:修改查询语句直接返回单个对象(推荐,更高效)
const query = `*[type == "project" && _id == "${params.id}"][0]`;
const project = await client.fetch(query, { cache: 'force-cache' });

2. 校验文档 _id 格式

Sanity 草稿文档的 ID 带 drafts. 前缀,正式发布的文档 ID 为纯字符串。如果 params.id 不带前缀,但目标文档是草稿状态,会匹配失败。

可修改查询语句兼容两种情况:

const query = `*[_type == "project" && (_id == "${params.id}" || _id == "drafts.${params.id}")][0]`;

3. 修正 API Token 配置

NEXT_PUBLIC_ 前缀的环境变量会暴露给客户端,如需访问私有数据,改用服务器端环境变量(比如 SANITY_API_TOKEN,去掉 NEXT_PUBLIC_),同时确保 Token 拥有至少 read 权限。

4. 临时禁用缓存测试

force-cache 会缓存空结果,可临时改为 no-store 验证是否是缓存问题:

const project = await client.fetch(query, { cache: 'no-store' });

5. 检查 API 版本与数据集

建议使用较新的 Sanity API 版本(比如 2024-05-01),同时确认 dataset 配置与数据所在数据集一致(比如是否误写为 production,实际数据在 development)。


修复后完整页面示例

import React from 'react'
import { client } from '@/lib/sanityClient';

export default async function Page({params}) {
  // 使用参数化查询,避免注入风险
  const query = `*[_type == "project" && _id == $id][0]`;
  
  // 参数化传参更安全
  const project = await client.fetch(query, { id: params.id }, { cache: 'no-store' });

  if (!project) {
    return <div>项目不存在</div>;
  }

  console.log(project);

  return (
    <div>
      <h1> Dummy static text</h1>
      <h1>{project.name}</h1>
      <p>{project.description}</p>
    </div>
  )
}

内容的提问来源于stack exchange,提问作者André Gomes

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 14:45:10