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

Sanity Webhook同步Stripe产品时Size的_id缺失问题排查

问题:Stripe Webhook无法获取Size对象的_id导致price_id无法回写Sanity

我开发了一个Webhook,可自动触发在Stripe中创建产品,同步标题、尺寸及关联价格,但无法将Stripe生成的price_id回写至Sanity的对应字段。持续收到以下错误:

Size ID is missing for this size: { size: '10x10', price: 100, lookup_key: null, price_id: null }

经确认,每个Size对象在Sanity Vision查询时确实存在_id,但尝试多种解构方式仍无法获取该字段。以下是Webhook代码:

const stripe = new Stripe(process.env.STRIPE_SECRET_KEY as string, {
  apiVersion: '2024-06-20',
});

export async function POST(req: NextRequest) {
  try {
    const { _id, title, sizes, image } = await req.json();

    if (!title) {
      console.log('Missing required param: name.');
      return NextResponse.json({ error: 'Missing required param: name.' }, { status: 400 });
    }

    console.log('Received product data:', { _id, title, sizes, image });

    let stripeProduct;
    try {
      stripeProduct = await stripe.products.retrieve(_id);
      console.log('Product already exists in Stripe:', stripeProduct.id);
    } catch (error: any) {
      if (error.code === 'resource_missing')') {

        stripeProduct = await stripe.products.create({
          id: _id,
          name: title,
          images: [image],  
          metadata: {
            sanity_id: _id,
          },
        });
        console.log('Created new Stripe product:', stripeProduct.id);
      } else {
        throw error; 
      }
    }

    
    for (const size of sizes) {
      const { size: sizeName, price, price_id, _id: sizeId } = size;
      console.log('Size object received:', size);

      console.log('Processing size:', { sizeName, price, price_id, sizeId });
      

      if (!sizeId) {
        console.error('Size ID is missing for this size:', size);
        continue; 
      }

      if (price_id) {
        console.log('Price ID exists, creating a new price...');
        const newPrice = await stripe.prices.create({
          unit_amount: price * 100,
          currency: 'gbp',
          product: stripeProduct.id,
        });

        await updateSanityPriceId(sizeId, newPrice.id);
      } else {
        console.log('No Price ID, creating a new price...');
        const newPrice = await stripe.prices.create({
          unit_amount: price * 100,
          currency: 'gbp',
          product: stripeProduct.id,
        });

        await updateSanityPriceId(sizeId, newPrice.id);
      }
    }

    return NextResponse.json({ message: 'Product and prices synced with Stripe successfully.' });
  } catch (error) {
    console.error('Error syncing with Stripe:', error);
    return NextResponse.json({ message: 'Internal Server Error' }, { status: 500 });
  }
}

async function updateSanityPriceId(sizeId: string, priceId: string) {
  try {
    const response = await fetch(`https://${process.env.NEXT_PUBLIC_SANITY_PROJECT_ID}.api.sanity.io/v2024-06-20/data/mutate/production`, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        Authorization: `Bearer ${process.env.SANITY_WRITE_TOKEN}`,
      },
      body: JSON.stringify({
        mutations: [
          {
            patch: {
              _id: sizeId,
              set: { price_id: priceId },
            },
          },
        ],
      }),
    });

    const result = await response.json();
    if (result.error) {
      console.error('Error from Sanity:', result.error);
    } else {
      console.log('Updated Sanity with new price ID:', result);
    }
  } catch (error) {
    console.error('Error updating Sanity with new price ID:', error);
  }
}

解决方案

  1. 修复语法错误
    代码中catch块存在多余引号,导致代码执行异常:

    // 错误写法
    if (error.code === 'resource_missing')') {
    // 正确写法
    if (error.code === 'resource_missing') {
    }
    
  2. 确认请求体中的Size字段
    在POST函数开头打印完整请求数据,确认sizes数组中的每个对象是否真的包含_id:

    const fullData = await req.json();
    console.log('Full request payload:', fullData);
    
  3. 调整解构方式
    避免解构失败,直接访问字段而非解构:

    // 替换原解构代码
    const sizeName = size.size;
    const price = size.price;
    const price_id = size.price_id;
    const sizeId = size._id; // 直接访问size._id
    
  4. 检查Sanity Webhook投影配置
    确认Sanity的Webhook是否返回了Size对象的_id字段。在Sanity Webhook设置中,调整Projection参数,确保包含所需字段:

    {_id, title, sizes[]{_id, size, price, price_id}, image}
    
  5. 优化重复代码
    原代码中price_id存在/不存在的分支逻辑完全一致,可合并简化:

    console.log(price_id ? 'Price ID exists, creating a new price...' : 'No Price ID, creating a new price...');
    const newPrice = await stripe.prices.create({
      unit_amount: price * 100,
      currency: 'gbp',
      product: stripeProduct.id,
    });
    await updateSanityPriceId(sizeId, newPrice.id);
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 12:54:52