• 【可能史上最全汇总】vue项目中【H5】如何处理后端返回的支付宝form表单,如何实现支付跳转?


    背景: 现在的项目,都需要付款,难免涉及支付宝或者微信支付。如果是支付宝支付,很多人都说,都已经2202年了,支付宝返回的还是form表单,然后,唤起支付宝的界面。
        一般来说,支付宝分为前端发起支付,和后台发起支付两种:
    ①前端发起支付,首先向后台发送订单数据,生成订单。然后,由前端调起手机的支付进行付款;
    ②如果采用的是,后台发起支付的方式,得到的返回是一个 < form >< /form >的表单html结构,自带< script >里面写的是监听提交按钮事件< /script >标签;
    简单来说,由后台发起的支付会返回一个form表单,调用表单中的submit方法唤起支付宝界面。

    一、实现思路

        首先,明确业务逻辑,支付跳转之前必然有一个提交订单信息【post】的过程,而我们的整个支付表单form是【post】之后返回发结果。返回的字符串结果如下所示:
    在这里插入图片描述

    在这里插入图片描述
    整理一下,整个的支付流程(此流程,仅针对本公司业务,仅做参考):
    ①生成token,createToken;
    ②创建订单createOrder,生成orderCoder(ps:后面获取订单详情需要用到);
    H5通过post接口调用,返回form表单(网上大多数案例,就是指的这一步);
    ④H5和步骤③同时发起,获取订单详情来轮询支付结果,最后,返回支付成功or支付失败的结果(ps:这个流程,后台调用前端无法拿到支付后的回调,目前,采取轮询调取后台支付状态的一个接口)。

    二、相关代码

    前端相关代码:
    2.1 方法一:使用document.forms[0].submit(),提交表单操作
    (1)首先,把表单的内容放在一个页面中:

    <div class="aliform" v-html="aliform"></div>
    
    • 1

    (2)通过document.forms[0].submit(),获取当前页面的第一个表单提交:

    <script>
    export default {
    	data() {
    	    return {
    	      aliform: "",
    	    };
      	},
      	methods: {
    		async iosAlipay(orderCode) {
          		let data = await requestAlipay(orderCode);
          		if (data.code == 20000) {
            		this.aliform = data.data;  //data.data就是支付宝返回给你的form,获取到的表单内容,具体样子可见上面的图片
            		this.$nextTick(() => {
            			// 获取订单详情来轮询支付结果
              			this.getOrderDetail();  
              			console.log(document.forms);  //跳转之前,可以先打印看看forms,确保后台数据和forms正确,否则,可能会出现一些奇奇怪怪的问题 ╮(╯▽╰)╭
              			document.forms[0].submit();  //重点--这个才是跳转页面的核心,获取第一个表单并提交
            		});
          		}
        	},
        	// 轮询结果
    	    getOrderDetail() {
    	    //轮询方法,因为支付是跳转到第三方支付宝,我们无法获知用户是否支付成功,或者用户支付成功后是否跳转回来。轮询方法,在一定时间内
    	      clearTimeout(this.timer);
    	      this.timer = setTimeout(() => {
    	        let initTime = +new Date();
    	        let loop = () => {
    	          getOrderDetail({ orderCode: this.orderCode}).then((res) => {
    	            if (res.code == 20000 && res.data && res.data.payStatus == 30) {
    	              //支付成功的相关操作
    	            } else {
    	              let now = +new Date();
    	              if (now - initTime < 45000) {
    	                loop();
    	              } else {
    	                // 超时按照失败处理
    	                //支付失败的结果
    	              }
    	            }
    	          });
    	        };
    	        loop();
    	      }, 500);
    	    },
    	}
    }
    </script>
    <style lang="less" scoped >
    .aliform {
      width: 1px;
      height: 1px;
      opacity: 0;
    }
    </style>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54

    (3)题外话–了解一下js提供的document.forms方法:

    (1)document.forms //表示获取当前页面的所有表单;
    (2)document.forms[0] //表示获取当前页面的第一个表单;
    (3)document.forms['exportServlet'] //表示获取当前页面的name="exportServlet"的表单
    (4)submit() //表示提交函数
    
    • 1
    • 2
    • 3
    • 4

    2.2 方法二:使用document.write(),就是重定向,覆盖原始页面

    \\ 假设result是后端返回的from字符串
    const newWindow = window.open('', '_self');  
    newWindow.document.write(result);
    newWindow.focus();
    
    • 1
    • 2
    • 3
    • 4

    或者,直接使用document.write(xxx),来进行支付跳转

    await postUserinfo('接口入参').then(res=>{
    	document.write(res.data.result)
    })
    
    • 1
    • 2
    • 3

    如果是在PC端处理,这种方式是没有问题的,但是需要注意三个问题:
    ①window.open()在接口回调中触发,可能会被游览器拦截;
    ②如果本身页面的地址是https的,如果返回的form的action是http的,游览器也会弹出安全提示;
    ③微信环境window.open()不生效。
    2.3 方法三:动态创建div容器,将form渲染进去,js触发form提交
    虽然,返回到result的form外面有html包裹,但是,可以动态的创建一个div容器,然后,将包含< html >的result渲染进去,通过js触发form表单的提交。

    const div = document.createElement('formdiv');
    div.innerHTML = result;
    document.body.appendChild(div);
    document.forms['cashierSubmit'].setAttribute('target', '_self');
    document.forms['cashierSubmit'].submit();
    div.remove();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    对于H5来说,这种方案兼容性更好。需要注意的是:
    一开始,将form的target设置成_blank,导致在ios上的游览器(微信环境,safari,UC)都无法实现form表单的提交。改成_self之后,问题解决。

    或者,这样也可:

    let divForm = document.getElementsByTagName('divform')
    if (divForm.length) {
        document.body.removeChild(divForm[0])
    }
    const div = document.createElement('divform')
    div.innerHTML = res.data // res.data就是支付宝返回给你的form
    document.body.appendChild(div)
    // document.forms[0].setAttribute('target', '_blank') // 加了_blank可能出问题所以我注释了
    document.getElementById('alipay_submit').submit()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    又或者,试下这样:

     //将接口返回的Form表单显示到页面
     document.querySelector('body').innerHTML = res.data; // res.data就是支付宝返回给你的form
     //调用submit 方法
     document.forms[0].submit()
    
    • 1
    • 2
    • 3
    • 4
    参考博客:

    UNI-APP解析支付宝返回FORM表单,唤起支付宝界面 https://www.freesion.com/article/6241970398/
    Vue完美解决支付宝返回的form表单问题,这可能是最有效的解决办法了 https://blog.zixutech.cn/archives/324
    vue项目中后端返回的支付宝form表单,怎么实现支付跳转? https://blog.csdn.net/qq_45934004/article/details/126156546
    Vue自动提交form表单后,自动跳转第三方页面 https://www.jianshu.com/p/e2323b4e2cf9
    开发笔记之uniapp 支付宝支付返回form表单解决方案 http://blog.haiya360.com/archives/766.html
    vue 支付宝返回url 新窗口打开 https://blog.csdn.net/wax9092/article/details/86631151
    H5处理支付宝接口返回form https://www.jianshu.com/p/8c5375671495
    vue项目中后端返回的支付宝form表单,怎么实现支付跳转? https://blog.csdn.net/qq_45934004/article/details/126156546
    Vue完美解决支付宝返回的form表单问题,这可能是最有效的解决办法了 https://blog.zixutech.cn/archives/324

  • 相关阅读:
    穿越物联网的迷雾:深入理解MQTT协议
    (附源码)springboot车辆管理系统 毕业设计 031034
    JavaScript操作DOM元素的一些基础方法与属性
    Spring源码--容器的基本实现与BeanDefinition
    Java高级编程day22【谷】
    设计模式基础前奏(上)
    【大揭秘】美团面试题:ConcurrentHashMap和Hashtable有什么区别?一文解析!
    最新Unity DOTS教程之BlobAsset核心机制分析
    Linux ____02、Linux开关机、目录介绍、文件目录相关命令(常用命令)
    23设计模式之 --------- 工厂模式
  • 原文地址:https://blog.csdn.net/qq_26780317/article/details/126605149