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

Flutter WebView中PayTM Checkout JS自定义重定向失效问题

问题场景

在Flutter WebView中集成Paytm Checkout JS时,商户配置项redirect参数设为false,目标是在transactionStatus回调返回交易状态后,通过POST表单提交跳转到自有页面paymentReceipt.php做后续处理。该逻辑在桌面浏览器可正常运行,但在Flutter WebView环境中,交易完成后不会跳转至自有页面,反而直接跳转Paytm官方结果页。

核心实现代码如下:

"merchant": {
    "redirect": false
},
"handler": {
   "notifyMerchant": function(eventName,data){
        console.log("notifyMerchant handler function called");
        console.log("eventName => ",eventName);
        console.log("data => ",data);
    },
   transactionStatus: function(data){
        console.log("payment status ", data);  
        var form = document.createElement('form');
        document.body.appendChild(form);
        form.method = 'post';
        form.action = 'https://<myWebsite>/paymentReceipt.php';
        for (var name in data) {
            var input = document.createElement('input');
            input.type = 'hidden';
            input.name = name;
            input.value = data[name];
            form.appendChild(input);
        }
         form.submit();
    },
}
问题根因
  • 跨域表单拦截:Paytm收银台运行在Paytm官方域名下,动态创建的隐藏表单提交到自有域名属于跨域POST请求,移动端WebView内核默认对这类跨域DOM导航做拦截,表单提交动作不会实际触发。
  • SDK环境兼容逻辑:Paytm Checkout JS内置UA检测,即使显式配置redirect: false,当识别到运行环境是移动端WebView时,会强制覆盖配置,在transactionStatus回调触发后立刻执行内置的官方结果页跳转,写在回调里的DOM表单操作在事件队列中优先级低于SDK内置逻辑,还没执行完成就被SDK触发的跳转打断。
  • 导航规则缺失:未配置WebView的导航拦截逻辑时,Paytm触发的官方页跳转请求不会被阻止,会被WebView优先加载。
排查解决步骤
  1. 配置WebView导航拦截规则
    以官方webview_flutter插件为例,重写导航代理,拦截Paytm官方结果页的跳转请求,只允许自有业务页面加载:
    final WebViewController controller = WebViewController()
      ..setNavigationDelegate(
        NavigationDelegate(
          onNavigationRequest: (request) {
            // 匹配Paytm官方支付结果页路径,直接拦截阻止加载
            if (request.url.contains('paytm.com/merchant-payment-response') 
                || request.url.contains('paytm.com/payment-status')) {
              return NavigationDecision.prevent;
            }
            // 自有域名页面允许正常加载
            if (request.url.contains('<myWebsite>/paymentReceipt.php')) {
              return NavigationDecision.navigate;
            }
            return NavigationDecision.navigate;
          },
        ),
      );
    
  2. 废弃JS侧动态表单提交逻辑,改用JS Channel传值给原生处理
    不要在JS上下文里操作DOM触发跳转,支付场景下JS和原生通信的稳定性远高于JS内DOM操作。首先在WebView初始化时注册JS通信通道:
    controller.addJavaScriptChannel(
      'PaytmTxnChannel',
      onMessageReceived: (message) {
        // 拿到交易数据JSON,直接由原生侧控制后续跳转
        final Map<String, dynamic> txnData = jsonDecode(message.message);
        // 后续可选择:
        // - 构造POST请求加载paymentReceipt.php
        // - 直接跳转Flutter原生支付结果页,体验更流畅
        // - 把交易数据提交给自有服务端做验签后再渲染结果
      },
    );
    
    同步修改Paytm JS侧的回调逻辑,拿到交易数据后直接传给原生,同时阻止SDK默认跳转:
    "handler": {
      notifyMerchant: function(eventName,data){
        console.log("notifyMerchant handler function called");
        console.log("eventName => ",eventName);
        console.log("data => ",data);
      },
      transactionStatus: function(data){
        console.log("payment status ", data);
        // 阻止事件冒泡,打断SDK内置跳转逻辑
        if (window.event) {
          window.event.stopPropagation();
          window.event.preventDefault();
        }
        // 移除Paytm挂载的收银台DOM,避免SDK后续触发跳转
        document.querySelector('#paytm-checkout-container')?.remove();
        // 把交易数据传给Flutter原生侧
        if (window.PaytmTxnChannel) {
          window.PaytmTxnChannel.postMessage(JSON.stringify(data));
        }
      },
    }
    
  3. 兼容端侧WebView配置(可选)
    Android端需要放开WebView的JS执行权限、跨域表单提交权限:
    if (Platform.isAndroid) {
      controller
        ..setJavaScriptMode(JavaScriptMode.unrestricted)
        ..runJavaScript('''
          // 重写表单提交方法,避免被Paytm SDK劫持
          HTMLFormElement.prototype.submit = function() {
            window.location.replace(this.action);
          }
        ''');
    }
    
    iOS端WKWebView默认放开相关权限,只需要正确实现导航代理的拦截逻辑即可。

注意:支付类场景不要依赖前端JS做最终跳转和数据处理,拿到交易数据后一定要先传给自有服务端做验签,再展示支付结果,避免前端篡改交易状态造成资损。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 04:01:13