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

Node.js开发Shopify应用访问localhost报重定向过多如何解决

问题原因

当前代码存在核心问题触发无限重定向:

  1. 路由逻辑缺失:仅配置了未授权时跳转/login的规则,未实现/login和OAuth回调路径的处理逻辑,所有请求(包括发往/login的请求)都会进入默认分支,被再次重定向到/login,形成死循环。
  2. Shopify场景适配错误:直接读取环境变量固定的SHOP值判断授权状态,没有从请求query参数中读取当前访问的真实店铺域名;同时嵌入式应用在iframe加载时直接返回302会触发跨域拦截,导致跳转无法正常完成,一直重复触发重定向判定。
    另外本地调试时如果直接用localhost作为HOST,没有用公网隧道工具映射本地端口,Shopify无法完成OAuth回调写入会话,也会持续判定未授权造成重定向循环。
修复步骤
  • 补全路由分支:单独处理/login(发起OAuth授权请求)和/auth/callback(校验授权回调、存储会话)两个路径,避免这两个路径被未授权重定向规则拦截。
  • 修正店铺读取逻辑:从请求的query参数中获取当前访问的shop参数,用该值作为key查询本地存储的授权会话,不要使用环境变量中的固定SHOP值。
  • 适配嵌入式应用跳转逻辑:检测到请求在iframe内发起时,不要直接返回302响应,返回搭载App Bridge跳转逻辑的页面,通过Shopify官方桥接能力完成跳转,避免跨域拦截。
  • 本地调试时使用隧道工具将本地3000端口映射为可公网访问的HTTPS地址,将该地址填入环境变量的HOST字段和Shopify合作伙伴后台的应用允许重定向地址列表。

核心修复后的路由代码如下:

async function onRequest(
    request: http.IncomingMessage,
    response: http.ServerResponse,
  ): Promise<void> {
    const {headers, url: req_url} = request;
    const pathName: string | null = url.parse(req_url).pathname;
    const queryString: string = String(url.parse(req_url).query);
    const query: Record<string, any> = querystring.parse(queryString);
  
    switch (pathName) {
      // 登录路径:发起OAuth跳转
      case '/login':
        const shop = query.shop?.toString() || SHOP;
        const authStartUrl = await Shopify.Auth.beginAuth(
          request,
          response,
          shop,
          '/auth/callback',
          false
        );
        response.writeHead(302, {Location: authStartUrl});
        response.end();
        return;
      // OAuth回调路径:校验授权、存储会话
      case '/auth/callback':
        try {
          const session = await Shopify.Auth.validateAuthCallback(
            request,
            response,
            query as unknown as AuthQuery
          );
          ACTIVE_SHOPIFY_SHOPS[session.shop] = session.accessToken;
          response.writeHead(302, {Location: `/?shop=${session.shop}&host=${query.host}`});
        } catch(e) {
          response.writeHead(500);
          response.write('OAuth校验失败,请检查密钥配置');
        }
        response.end();
        return;
      default:
        const currentShop = query.shop?.toString();
        // 未找到当前店铺授权信息,触发登录跳转
        if (!currentShop || ACTIVE_SHOPIFY_SHOPS[currentShop] === undefined) {
          // iframe场景用App Bridge跳转,避免跨域302拦截
          if (headers['sec-fetch-dest'] === 'iframe') {
            response.writeHead(200, {'Content-Type': 'text/html'});
            response.write(`
              <script src="https://unpkg.com/@shopify/app-bridge@3"></script>
              <script>
                const AppBridge = window['app-bridge'];
                const createApp = AppBridge.default;
                const Redirect = AppBridge.actions.Redirect;
                const app = createApp({
                  apiKey: '${API_KEY}',
                  host: '${query.host || ""}'
                });
                const redirect = Redirect.create(app);
                redirect.dispatch(
                  Redirect.Action.REMOTE,
                  '/login?shop=${currentShop || SHOP}'
                );
              </script>
            `);
          } else {
            response.writeHead(302, {Location: `/login?shop=${currentShop || SHOP}`});
          }
          response.end();
          return;
        }
        // 已授权正常返回内容
        response.write('Hello world!');
        response.end();
        return;
    }
  }
调试方法
  • 打开浏览器开发者工具的网络面板,勾选「保留日志」选项,查看每一次重定向的请求路径和响应头,若发现请求在/和/login之间反复跳转,优先检查路由匹配规则是否覆盖了/login路径。
  • 若重定向时控制台出现跨域相关报错,说明是iframe内302被拦截,替换为App Bridge跳转即可。
  • 若OAuth回调请求没有进入服务端日志,检查HOST配置是否为公网可访问的HTTPS地址,是否已将回调地址加入Shopify后台的允许列表。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.01 01:57:10