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

Node.js+Express下Shopify REST API分页请求问题求助

Shopify REST API 分页解决方案(Express + 前端)

问题根源

  1. 前端直接请求Shopify URL触发CORS/401:Shopify Admin API的CORS策略禁止浏览器端直接发起请求,且前端无法安全携带Access Token,必然触发401权限错误。
  2. 服务端直接用完整分页URL请求失败:Shopify官方Rest客户端要求基于店铺域名构造请求,无需传入完整外部URL,直接传递page_info参数即可。

解决方案

1. 修改服务端接口,支持分页参数

更新你的/inventory接口,接收page_info参数,用Shopify客户端构造分页请求:

protectedRouter.get('/inventory', async (req, res) => {
  try {
    const session = await Shopify.Utils.loadCurrentSession(req, res);
    const client = new Shopify.Clients.Rest(session.shop, session.accessToken);
    
    // 构造请求参数:默认每页50条,若有page_info则带上
    const requestParams = {
      limit: 50
    };
    if (req.query.page_info) {
      requestParams.page_info = req.query.page_info;
    }

    const result = await client.get({
      path: 'products',
      query: requestParams,
    });

    res.render('inventory', {
      products: result,
    });
  } catch (error) {
    console.error('库存加载失败:', error);
    res.status(500).send('加载库存出错');
  }
});

2. 调整前端模板,传递分页游标而非完整URL

不再输出Shopify的完整分页URL,改用隐藏字段存储page_info游标:

script(src="/scripts/pagination.js")
div.View
  h3.title.my-4 Etat des stocks
  div.row
    div.col-6
      <!-- 无上一页时禁用按钮 -->
      button.btn.btn-outline-dark.ml-4(id="previous_btn" #{!products.pageInfo.prevPageInfo ? 'disabled' : ''})
        i(class="bi bi-arrow-left-circle-fill") Précédent
      <!-- 存储上一页游标 -->
      input(type="hidden" id="prevPageInfo" value="#{products.pageInfo.prevPageInfo || ''}")
    div.col-6
      <!-- 无下一页时禁用按钮 -->
      button.btn.btn-outline-dark.float-right.mr-4(id="next_btn" #{!products.pageInfo.nextPageInfo ? 'disabled' : ''}) Suivant 
        i(class="fa-solid fa-circle-arrow-right")
      <!-- 存储下一页游标 -->
      input(type="hidden" id="nextPageInfo" value="#{products.pageInfo.nextPageInfo || ''}")

3. 前端分页逻辑:调用自身服务端接口

点击按钮时,请求自己的Express接口并传递page_info参数,避免直接请求Shopify:

window.addEventListener('DOMContentLoaded', () => {
  const nextBtn = document.getElementById('next_btn');
  const prevBtn = document.getElementById('previous_btn');
  const nextPageInfo = document.getElementById('nextPageInfo').value;
  const prevPageInfo = document.getElementById('prevPageInfo').value;

  // 下一页请求
  nextBtn.onclick = async () => {
    if (!nextPageInfo) return;
    try {
      const res = await fetch(`/inventory?page_info=${nextPageInfo}`);
      if (res.ok) {
        // 替换页面内容实现刷新
        document.body.innerHTML = await res.text();
      }
    } catch (err) {
      console.error('加载下一页失败:', err);
    }
  };

  // 上一页请求
  prevBtn.onclick = async () => {
    if (!prevPageInfo) return;
    try {
      const res = await fetch(`/inventory?page_info=${prevPageInfo}`);
      if (res.ok) {
        document.body.innerHTML = await res.text();
      }
    } catch (err) {
      console.error('加载上一页失败:', err);
    }
  };
});

关键注意事项

  • 绝对不能暴露Access Token:所有Shopify API请求必须通过服务端代理,避免Token在前端泄露。
  • 使用游标分页:Shopify REST API的分页依赖page_info游标,而非传统页码,必须用接口返回的prevPageInfo/nextPageInfo构造下一次请求。
  • 局部刷新优化:如果不想替换整个页面,可以让服务端返回JSON格式的商品数据,前端仅更新商品列表区域,提升体验。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 11:57:25