学习笔记:记录前端在对接支付功能需要做什么,整个流程是什么样的,以支付宝为例。
PC网站不可以接入微信支付功能
先了解一个前置知识:
支付宝和微信一个巨大区别就是:微信目前不支持PC网站接入支付功能,我们如果想要接入微信,只能是去开发原生APP,服务号,小程序,支付宝则支持PC网站接入支付功能。
developers.weixin.qq.com/community/d…
一:前置条件-开放平台的注册
在接入支付宝支付功能之前,我们需要先去支付宝开放平台注册,让自己的网站有资格接入支付功能,这一步骤一般不是程序员来做的,我们在此不做介绍。
如果是个人开发者开发了某个项目,想接入支付宝的支付功能,则必须要有支付宝企业账号,才能注册成功。具体步骤支付宝开放平台有介绍。
二:对接前准备工作-配置开发设置
在真正写代码对接之前,我们需要先做一系列基础配置,具体配置文档可以查看:接入准备-支付宝文档中心
具体要配置以下重要信息:
- 接口加签方式:必填。 用于保障商户应用和支付宝交互的安全性,配置详情参见 接口加签方式配置说明。
- IP白名单:选填。 用于保障用户资金安全,说明详情参见 IP 白名单接入指南。
- 应用网关:选填。 用于接收支付宝异步通知消息,说明详情参见 应用网关。
- 接口内容加密方式:选填。用于加/解密 OpenAPI bizContent 报文内容及加/解密部分用户隐私信息,说明详情参见 接口内容加密方式。
- 授权回调地址:选填。 第三方应用授权 或 [用户信息授权](opendocs.alipay.com/open/284/we… redirect_uri 的说明) 后回调地址。授权链接中配置的 redirect_uri 的值必须与此值保持一致 (如:www.alipay.com) ,用户成功授权后将在该 url 后携带授权码等信息并跳转至该页。当填入该地址时,系统会自动进行安全检测,详情请参考 安全检测。
三:整体对接流程-技术对接前后端都做了什么
- 用户在前端页面点击支付宝支付功能
- 前端调用服务端接口
- 服务端接收到请求,利用
alipay-sdk(nodejs)创建支付订单信息,得到支付宝返回的url - 服务端需要对该
url进行encode(encodeURIComponent)操作,以防止意外的转码 - 服务端返回该
url(encode 之后的)到前端 - 前端进行
decode解码,得到支付的url - 前端控制跳转到该
url,即为 支付宝用户支付页面 - 用户在该页面完成支付,支付完成之后,支付宝会回调两个地址:
returnUrl:支付完成的跳转地址,用于用户视觉感知支付已成功notifyUrl:异步通知地址,以http或者https开头的,商户外网可以post访问的异步地址,用于接收支付宝返回的支付结果。
- 前端通过
returnUrl告知用户支付完成 - 服务端通过
notifyUrl完成用户支付之后的数据变更,同时需要对通知信息进行 验签 操作,并且在验签通过之后返回success给支付宝 - 区分
PC端支付和移动端支付的关键在于:- 电脑端:服务端触发的接口为
alipay.trade.page.pay - 移动端:服务端触发的接口为
alipay.trade.wap.pay
- 电脑端:服务端触发的接口为
整个流程,工作量主要在后端,前端需要做的事情比较少。
四:对接-前端代码的实现
交互流程
整个支付过程的交互流程,一共分为四步:
- 用户点击支付,页面新打开一个页签跳转到支付页面
- 用户扫码支付。
- 支付成功后,页面跳转回商家页面
- 商家页面确认是否已经交易成功,根据是否交易成功给出下一步交互。
涉及接口
由以上流程可知,整个支付流程,前端一般只会涉及到两个接口:
- 用户点击支付时,下订单接口,此接口会二维码的url
- 支付成功,跳回商家页面时候,商家查询是否支付成功的接口
代码实现
定义下单接口和查询支付结果接口
/**
* 支付下单
*/
export const getAliPay = (subject, totalAmount, body, isMobile) => {
return request({
url: '/user/alipay',
params: {
subject,
totalAmount,
body,
isMobile
}
})
}
/**
* 获取支付接口
*/
export const getPayResult = (out_trade_no) => {
return request({
url: '/sys/pay/result',
params: {
out_trade_no
}
})
}
定义用户点击支付事件和支付工具类,当用户点击后发送下单接口,然后跳转到二维码支付页面
const props = defineProps({
payData: {
required: true,
type: Object
}
})
const onAliPayClick = () => {
alipay(props.payData.title, props.payData.desc)
}
// 定义支付工具类
import store from '@/store'
import { getAliPay } from '@/api/pay'
import { isMobileTerminal } from '@/utils/flexible'
/**
* 触发支付宝支付
* @param {*} title 支付标题
* @param {*} desc 支付描述
*/
export const alipay = async (title, desc) => {
// encode 的支付地址
const { encodeURI } = await getAliPay(
title,
'0.01',
desc,
isMobileTerminal.value
)
// 解构
window.location.href = decodeURIComponent(encodeURI)
}
支付成功后,会跳回至商家指定的页面,在这个页面我们需要查询是否交易成功
<template>
<!-- 商家回调页面 -->
</template>
<script setup>
import { ref } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { getPayResult } from '@/api/pay'
import { useStore } from 'vuex'
const route = useRoute()
const router = useRouter()
const store = useStore()
const isSuccess = ref(null)
// 查询是否支付成功
const getResultData = async () => {
const res = await getPayResult(route.query.out_trade_no)
isSuccess.value = res
}
getResultData()
const onConfirm = () => {
store.dispatch('user/profile')
router.push('/')
}
</script>