Shopify付费嵌入式应用 内嵌加载计费确认URL实现方法
问题原因
你当前的实现存在三个核心问题,导致计费确认流程跳出嵌入式iframe加载外部页面:
- 服务端直接调用
ctx.redirect(confirmationUrl)属于顶层302重定向,会冲破Shopify后台的iframe容器,直接触发顶层页面跳转 - 配置的
returnUrl值为www.abc.com,既没有带HTTPS协议头,也不是你自身应用的嵌入式入口路径,用户批准计费后自然无法回到应用内部加载 - 没有通过Shopify App Bridge提供的跳转能力触发计费页,Shopify无法识别当前是嵌入式应用场景,不会做iframe内的路由兼容
修复方案
按照以下步骤调整代码即可实现整个计费流程在嵌入式应用内部完成:
- 修正计费接口的returnUrl配置,地址必须为你自身应用的合法入口路径,同时携带shop、host等必填参数,必须带HTTPS协议头
- 移除服务端直接重定向到confirmationUrl的逻辑,服务端仅负责生成计费确认地址,将地址传递给前端
- 前端拿到计费确认地址后,通过App Bridge提供的Redirect能力触发跳转,保证整个流程始终运行在嵌入式iframe容器内
修正后代码
getsubscriptionurl.js
export const getSubscriptionUrl = async (ctx, shop, host) => { const { client } = ctx; // 配置应用内的回跳地址,必须带HTTPS协议,携带shop和host参数 const returnUrl = `${process.env.HOST}/billing/success?shop=${shop}&host=${encodeURIComponent(host)}`; const confirmationUrl = await client .mutate({ mutation: RECURRING_CREATE(), variables: { returnUrl: returnUrl, } }) .then(response => response.data.appSubscriptionCreate.confirmationUrl); return confirmationUrl; };
server.js(afterAuth部分修正)
async afterAuth(ctx) { // Access token and shop available in ctx.state.shopify const { shop, accessToken, scope } = ctx.state.shopify; const host = ctx.query.host; ACTIVE_SHOPIFY_SHOPS[shop] = {scope:scope,accessToken:accessToken}; const response = await Shopify.Webhooks.Registry.register({ shop, accessToken, path: "/webhooks", topic: "APP_UNINSTALLED", webhookHandler: async (topic, shop, body) => delete ACTIVE_SHOPIFY_SHOPS[shop], }); if (!response.success) { console.log( `Failed to register APP_UNINSTALLED webhook: ${response.result}` ); } server.context.client = await handlers.createClient(shop, accessToken); // 获取计费确认地址,不要直接服务端重定向 const billingConfirmUrl = await handlers.getSubscriptionUrl(ctx, shop, host); // 跳回应用首页,将计费地址通过参数传递给前端 ctx.redirect(`/?shop=${shop}&host=${encodeURIComponent(host)}&billingUrl=${encodeURIComponent(billingConfirmUrl)}`); }
前端跳转逻辑(应用入口页添加)
import createApp from '@shopify/app-bridge'; import { Redirect } from '@shopify/app-bridge/actions'; // 从地址栏获取host参数初始化App Bridge const urlParams = new URLSearchParams(window.location.search); const host = urlParams.get('host'); const billingUrl = urlParams.get('billingUrl'); const app = createApp({ apiKey: process.env.SHOPIFY_API_KEY, host: host, }); // 检测到有待跳转的计费地址时,通过App Bridge触发跳转 if (billingUrl) { const redirect = Redirect.create(app); redirect.dispatch(Redirect.Action.REMOTE, decodeURIComponent(billingUrl)); }
注意事项
所有Shopify嵌入式应用内的跨域跳转(包括跳转计费页、跳转其他Shopify官方页面)都必须通过App Bridge的Redirect能力触发,禁止直接使用服务端302重定向、
window.location.href直接赋值等顶层跳转方式,否则一定会冲破iframe容器跳转到外部页面。用户批准计费后会自动跳回你配置的returnUrl,该地址属于你应用自身的路径,会直接在嵌入式iframe内加载展示。
内容的提问来源于stack exchange,提问作者Amal J
相关产品推荐
相关产品推荐

