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; } } }
可能原因
- Shopify API版本过期:当前使用的2021-07版本已超出Shopify的API支持周期,旧版本接口可能被废弃,导致返回数据结构异常或请求被拒绝。
- 集合Handle无效:Shopify后台中Handle为"frontpage"的集合被删除、重命名或Handle值被修改,导致
collectionByHandle查询返回null。 - Storefront Access Token异常:Token过期、权限被修改或未正确配置,导致无法通过API获取集合数据。
- 缺乏数据校验:代码中直接访问嵌套属性(如
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
相关产品推荐
相关产品推荐

