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

Shopify Node.js应用从后台打开时报错argument str must be a string 求助

问题修复:Shopify应用后台打开时触发argument str must be a string错误

错误原因

从Shopify后台点击已安装应用时,请求不会携带安装流程中设置的state Cookie,甚至req.headers.cookie可能为undefined。直接调用cookie.parse(req.headers.cookie)时,因为传入的是undefined而非字符串,就会抛出argument str must be a string错误。

另外,后台打开应用属于已授权后的正常访问,不需要走安装回调的state验证、token获取流程,当前代码把「安装回调请求」和「后台正常访问请求」混在一起处理了。

修复步骤

  1. 先校验req.headers.cookie是否存在,避免直接解析undefined
  2. 区分请求类型:只有当请求携带code参数时,才是安装回调请求,需执行state验证和token获取;无code参数时是后台正常访问,直接使用已存储的access_token拉取数据

修改后的代码示例

app.get('/shopify', (req, res) => {
  const shop = req.query.shop;

  if (!shop) { return res.status(400).send('no shop')}

  const state = nonce();

  const installShopUrl = buildInstallUrl(shop, state, buildRedirectUri())

  res.cookie('state', state, { 
    httpOnly: true, 
    secure: process.env.NODE_ENV === 'production', // 生产环境启用HTTPS
    sameSite: 'lax' 
  }) // 生产环境必须加密Cookie
  res.redirect(installShopUrl);
});

app.get('/shopify/callback', async (req, res) => {
  const { shop, code, state } = req.query;

  // 1. 先判断Cookie是否存在,避免解析undefined报错
  let stateCookie = null;
  if (req.headers.cookie) {
    stateCookie = cookie.parse(req.headers.cookie).state;
  }

  // 2. 区分安装回调和后台访问请求
  if (code) {
    // 安装回调流程:执行state验证和token获取
    if (!state || !stateCookie || state !== stateCookie) { 
      return res.status(403).send('Cannot be verified')
    }

    const { hmac, ...params } = req.query
    const queryParams = querystring.stringify(params)
    const hash = generateEncryptedHash(queryParams)

    if (hash !== hmac) { 
      return res.status(400).send('HMAC validation failed')
    }

    try {
      const data = {
        client_id: shopifyApiPublicKey,
        client_secret: shopifyApiSecretKey,
        code
      };
      const tokenResponse = await fetchAccessToken(shop, data)
      const { access_token } = tokenResponse.data

      // 关键:把access_token和店铺域名关联存储到数据库
      await saveShopToken(shop, access_token);

      const shopData = await fetchShopData(shop, access_token)
      res.send(shopData.data.shop)
    } catch(err) {
      console.log(err)
      res.status(500).send('something went wrong')
    }
  } else {
    // 后台正常访问流程:从数据库读取已存储的access_token
    if (!shop) {
      return res.status(400).send('no shop')
    }

    try {
      // 从数据库获取该店铺的access_token
      const access_token = await getShopToken(shop);
      if (!access_token) {
        // 无token时重定向到安装页面
        return res.redirect(`/shopify?shop=${shop}`);
      }

      const shopData = await fetchShopData(shop, access_token)
      res.send(shopData.data.shop)
    } catch(err) {
      console.log(err)
      res.status(500).send('something went wrong')
    }
  }
});

///////////// Start the Server /////////////

app.listen(PORT, () => console.log(`listening on port ${PORT}`));

额外注意事项

  • 生产环境必须加密state Cookie,同时设置httpOnly、secure、sameSite属性,防范XSS和CSRF攻击
  • 需自行实现saveShopToken和getShopToken方法,将access_token与店铺域名关联存储,后台访问时才能快速获取
  • 后台访问请求建议补充HMAC验证,拦截非法请求

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 05:10:38