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

Next.js对接Shopify时collectionByHandle未定义错误的排查与修复

问题:Next.js Shopify网站本地构建失败,出现「Cannot read properties of undefined (reading 'collectionByHandle')」错误

错误信息

error - lib/shopify.js (353:31) @ getProductsInCollection
TypeError: Cannot read properties of undefined (reading 'collectionByHandle')
  351 |       const cursor = response.data.products.edges[num - 1].cursor;
  352 | 
> 353 |       return data.concat(await recursiveCatalog(cursor));
      |                               ^
  354 |     } else {
  355 |       return data;
  356 |     }

相关代码片段

Shopify基础请求函数

const domain = process.env.SHOPIFY_STORE_DOMAIN
const storefrontAccessToken = process.env.SHOPIFY_STOREFRONT_ACCESSTOKEN

async function ShopifyData(query) {
  const URL = `https://${domain}/api/2021-07/graphql.json`

  const options = {
    endpoint: URL,
    method: "POST",
    headers: {
      "X-Shopify-Storefront-Access-Token": storefrontAccessToken,
      "Accept": "application/json",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ query })
  }

  try {
    const data = await fetch(URL, options).then(response => {
      return response.json()
    })

    return data
  } catch (error) {
    throw new Error("Products not fetched")
  }
}

获取集合商品函数

export async function getProductsInCollection() {
  const query = `
  {
    collectionByHandle(handle: "frontpage") {
      title
      products(first: 60) {
        edges {
          node {
            id
            title
            productType
            handle
            metafields(first: 2) {
              edges {
                  node {
                      namespace
                      key
                      value
                  }
              }
          }
        }
      }
    }
  }`
  const response = await ShopifyData(query);
  const allProducts = response.data.collectionByHandle.products.edges
    ? response.data.collectionByHandle.products.edges
    : [];
  return allProducts;
}

递归获取商品函数

export async function recursiveCatalog(cursor = '', initialRequest = true) {
  let data;

  if (cursor !== '') {
    const query = `{
      products(after: "${cursor}", first: 250) {
        edges {
          cursor
          node {
            id
            handle
          }
        }
        pageInfo {
          hasNextPage
        }
      }
    }`;

    const response = await ShopifyData(query);
    data = response.data.products.edges ? response.data.products.edges : [];

    if (response.data.products.pageInfo.hasNextPage) {
      const num = response.data.products.edges.length;
      const cursor = response.data.products.edges[num - 1].cursor;
      console.log('Cursor: ', cursor);

      return data.concat(await recursiveCatalog(cursor));
    } else {
      return data;
    }
  } else {
    const query = `{
      products(first: 250) {
        edges {
          cursor
          node {
            id
            handle
          }
        }
        pageInfo {
          hasNextPage
        }
      }
    }
    `;

    const response = await ShopifyData(query);
    data = response.data.products.edges ? response.data.products.edges : [];

    if (response.data.products.pageInfo.hasNextPage) {
      const num = response.data.products.edges.length;
      const cursor = response.data.products.edges[num - 1].cursor;

      return data.concat(await recursiveCatalog(cursor));
    } else {
      return data;
    }
  }
}

可能原因

  1. Shopify API版本过期:当前使用的2021-07版本已超出Shopify的API支持周期,旧版本接口可能被废弃,导致返回数据结构异常或请求被拒绝。
  2. 集合Handle无效:Shopify后台中Handle为"frontpage"的集合被删除、重命名或Handle值被修改,导致collectionByHandle查询返回null。
  3. Storefront Access Token异常:Token过期、权限被修改或未正确配置,导致无法通过API获取集合数据。
  4. 缺乏数据校验:代码中直接访问嵌套属性(如response.data.collectionByHandle.products.edges),未处理中间属性为undefined的情况,一旦某层数据缺失就会抛出错误。

修复方案

1. 更新Shopify API版本

将API版本替换为Shopify当前支持的稳定版本(如2024-04),修改ShopifyData函数中的URL:

const URL = `https://${domain}/api/2024-04/graphql.json`

Shopify API版本每季度更新,旧版本会在发布12个月后废弃,需确保使用未被标记为“废弃”的版本。

2. 验证集合Handle有效性

  • 登录Shopify后台,进入「产品」->「集合」,查找Handle为"frontpage"的集合,确认其存在且Handle未变更。
  • 若集合不存在或Handle修改,更新getProductsInCollection中的handle参数为正确值。
  • 可通过Shopify GraphiQL Explorer测试查询,确认collectionByHandle能正常返回数据。

3. 检查Storefront Access Token

  • 进入Shopify后台「应用」->「管理私有应用」,找到对应Token,确认其状态为“激活”。
  • 检查Token权限,确保拥有「读取产品」「读取集合」等Storefront API权限。
  • 若Token失效,重新生成新Token并更新本地环境变量文件(.env.local)。

4. 添加数据校验与错误处理

优化ShopifyData函数,处理GraphQL错误:

async function ShopifyData(query) {
  const URL = `https://${domain}/api/2024-04/graphql.json`

  const options = {
    method: "POST",
    headers: {
      "X-Shopify-Storefront-Access-Token": storefrontAccessToken,
      "Accept": "application/json",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ query })
  }

  try {
    const response = await fetch(URL, options);
    const data = await response.json();
    // 捕获GraphQL查询错误
    if (data.errors) {
      console.error('Shopify GraphQL错误:', data.errors);
      throw new Error('GraphQL查询失败');
    }
    return data;
  } catch (error) {
    console.error('请求失败:', error);
    throw new Error("商品数据获取失败");
  }
}

优化getProductsInCollection函数,逐层校验数据:

export async function getProductsInCollection() {
  const query = `
  {
    collectionByHandle(handle: "frontpage") {
      title
      products(first: 60) {
        edges {
          node {
            id
            title
            productType
            handle
            metafields(first: 2) {
              edges {
                  node {
                      namespace
                      key
                      value
                  }
              }
          }
        }
      }
    }
  }`;
  const response = await ShopifyData(query);
  // 使用可选链操作符逐层校验
  const collection = response?.data?.collectionByHandle;
  const allProducts = collection?.products?.edges || [];
  return allProducts;
}

优化recursiveCatalog函数,避免访问undefined属性:

export async function recursiveCatalog(cursor = '') {
  let data = [];
  const query = cursor 
    ? `{
        products(after: "${cursor}", first: 250) {
          edges {
            cursor
            node { id handle }
          }
          pageInfo { hasNextPage }
        }
      }`
    : `{
        products(first: 250) {
          edges {
            cursor
            node { id handle }
          }
          pageInfo { hasNextPage }
        }
      }`;

  const response = await ShopifyData(query);
  const products = response?.data?.products;
  
  if (products) {
    data = products.edges || [];
    if (products.pageInfo?.hasNextPage) {
      const lastEdge = products.edges[products.edges.length - 1];
      if (lastEdge?.cursor) {
        data = data.concat(await recursiveCatalog(lastEdge.cursor));
      }
    }
  }
  return data;
}

5. 确认环境变量配置

检查本地.env.local文件,确认SHOPIFY_STORE_DOMAIN和SHOPIFY_STOREFRONT_ACCESSTOKEN配置正确,无拼写错误。修改后重启Next.js开发服务器,确保环境变量生效。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 00:30:57