Node.js开发Shopify应用访问localhost报重定向过多如何解决
问题原因
当前代码存在核心问题触发无限重定向:
- 路由逻辑缺失:仅配置了未授权时跳转
/login的规则,未实现/login和OAuth回调路径的处理逻辑,所有请求(包括发往/login的请求)都会进入默认分支,被再次重定向到/login,形成死循环。 - 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
相关产品推荐
相关产品推荐

