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

如何配置Sanity实时预览?解决req.query为空导致resolveHref返回undefined问题

解决Sanity Next.js个人网站模板预览时req.query为空导致路由无法解析的问题

问题分析

使用Sanity提供的Next.js个人网站模板时,预览功能依赖req.query获取documentType和slug参数,但该对象为空,导致resolveHref返回undefined,无法完成预览跳转。

解决方案

1. 确认Sanity Studio预览参数传递正确

检查Sanity各文档类型的schema配置,确保预览URL携带了documentType、slug和secret参数:

// sanity/schemas/post.js 示例
export default {
  name: 'post',
  type: 'document',
  preview: {
    select: {
      title: 'title',
      slug: 'slug.current',
    },
    prepare(selection) {
      return {
        title: selection.title,
        subtitle: selection.slug,
        url: `/api/preview?documentType=post&slug=${selection.slug}&secret=${process.env.SANITY_PREVIEW_SECRET}`
      }
    }
  },
  // ... 其他schema配置
}

如果是首页这类无slug的文档,要传递特殊标识(比如slug=home),确保resolveHref能识别。

2. 适配Next.js路由模式的参数获取方式

  • Pages Router(原pages/api/preview.js):确认请求是GET方法,req.query仅在GET请求中生效。如果是POST请求,需改用req.body获取参数。
  • App Router(app/api/preview/route.js):Next.js 13+的App Router中,API路由需通过request.nextUrl.searchParams获取URL参数,替换原有的req.query:
import { NextResponse } from 'next/server'
import { createClient } from '@sanity/client'
import getSecret from '@/lib/getSecret'
import resolveHref from '@/lib/resolveHref'

const _client = createClient({ 
  projectId: process.env.NEXT_PUBLIC_SANITY_PROJECT_ID,
  dataset: process.env.NEXT_PUBLIC_SANITY_DATASET,
  apiVersion: '2024-01-01',
  useCdn: false
})

export async function GET(request) {
  const searchParams = request.nextUrl.searchParams
  const secret = searchParams.get('secret')
  const documentType = searchParams.get('documentType')
  const slug = searchParams.get('slug')

  const previewData = {}
  if (process.env.SANITY_REQUIRE_PREVIEW_SECRET === 'true' && !secret) {
    return new NextResponse('Invalid secret', { status: 401 })
  }

  if (secret) {
    const token = process.env.SANITY_API_READ_TOKEN
    if (!token) {
      throw new Error('SANITY_API_READ_TOKEN环境变量未配置')
    }
    const client = _client.withConfig({ token })
    const storedSecret = await getSecret(client, 'preview.secret')
    if (secret !== storedSecret) {
      return new NextResponse('Invalid secret', { status: 401 })
    }
    previewData.token = token
  }

  const href = resolveHref(documentType, slug)
  if (!href) {
    return new NextResponse('无法根据文档类型和slug解析预览URL', { status: 400 })
  }

  const response = NextResponse.redirect(new URL(href, request.url))
  response.cookies.set('__prerender_bypass', '1', { path: '/' })
  if (previewData.token) {
    response.cookies.set('sanity-preview-token', previewData.token, { path: '/' })
  }
  return response
}

3. 调试参数为空问题

在API路由中添加日志,确认请求参数是否正常传递:

// Pages Router示例
export default async function preview(req, res) {
  console.log('请求URL:', req.url)
  console.log('Query参数:', req.query)
  // ... 原有逻辑
}

如果日志中无参数,检查:

  • 请求是否为GET方法(POST请求参数在req.body)
  • Sanity Studio的预览URL是否拼写正确
  • 反向代理或CDN是否过滤了请求参数

4. 完善resolveHref函数逻辑

确保resolveHref能处理空slug或特殊文档类型的情况:

export function resolveHref(documentType, slug) {
  switch (documentType) {
    case 'post':
      return slug ? `/posts/${slug}` : null
    case 'page':
      return slug === 'home' ? '/' : `/${slug}`
    case 'project':
      return `/projects/${slug}`
    default:
      // 未匹配到类型时返回默认预览页或首页
      return '/'
  }
}

内容的提问来源于stack exchange,提问作者Burger Sasha

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 06:32:06