(学习笔记)PC网站对接第三方支付功能

297 阅读5分钟

学习笔记:记录前端在对接支付功能需要做什么,整个流程是什么样的,以支付宝为例。

PC网站不可以接入微信支付功能

先了解一个前置知识:
支付宝和微信一个巨大区别就是:微信目前不支持PC网站接入支付功能,我们如果想要接入微信,只能是去开发原生APP,服务号,小程序,支付宝则支持PC网站接入支付功能。

developers.weixin.qq.com/community/d… image.png

一:前置条件-开放平台的注册

在接入支付宝支付功能之前,我们需要先去支付宝开放平台注册,让自己的网站有资格接入支付功能,这一步骤一般不是程序员来做的,我们在此不做介绍。

如果是个人开发者开发了某个项目,想接入支付宝的支付功能,则必须要有支付宝企业账号,才能注册成功。具体步骤支付宝开放平台有介绍。

二:对接前准备工作-配置开发设置

在真正写代码对接之前,我们需要先做一系列基础配置,具体配置文档可以查看:接入准备-支付宝文档中心

具体要配置以下重要信息:

  1. 接口加签方式:必填。 用于保障商户应用和支付宝交互的安全性,配置详情参见 接口加签方式配置说明
  2. IP白名单:选填。 用于保障用户资金安全,说明详情参见 IP 白名单接入指南
  3. 应用网关:选填。 用于接收支付宝异步通知消息,说明详情参见 应用网关
  4. 接口内容加密方式:选填。用于加/解密 OpenAPI bizContent 报文内容及加/解密部分用户隐私信息,说明详情参见 接口内容加密方式
  5. 授权回调地址:选填。 第三方应用授权 或 [用户信息授权](opendocs.alipay.com/open/284/we… redirect_uri 的说明) 后回调地址。授权链接中配置的 redirect_uri 的值必须与此值保持一致 (如:www.alipay.com) ,用户成功授权后将在该 url 后携带授权码等信息并跳转至该页。当填入该地址时,系统会自动进行安全检测,详情请参考 安全检测image.png

三:整体对接流程-技术对接前后端都做了什么

image.png

  1. 用户在前端页面点击支付宝支付功能
  2. 前端调用服务端接口
  3. 服务端接收到请求,利用 alipay-sdk(nodejs) 创建支付订单信息,得到支付宝返回的 url
  4. 服务端需要对该 url 进行 encode(encodeURIComponent) 操作,以防止意外的转码
  5. 服务端返回该 url(encode 之后的) 到前端
  6. 前端进行 decode 解码,得到支付的 url
  7. 前端控制跳转到该 url ,即为 支付宝用户支付页面
  8. 用户在该页面完成支付,支付完成之后,支付宝会回调两个地址:
    1. returnUrl:支付完成的跳转地址,用于用户视觉感知支付已成功
    2. notifyUrl:异步通知地址,以http或者https开头的,商户外网可以post访问的异步地址,用于接收支付宝返回的支付结果。
  9. 前端通过 returnUrl 告知用户支付完成
  10. 服务端通过 notifyUrl 完成用户支付之后的数据变更,同时需要对通知信息进行 验签 操作,并且在验签通过之后返回 success 给支付宝
  11. 区分 PC端支付和移动端支付的关键在于:
    1. 电脑端:服务端触发的接口为 alipay.trade.page.pay
    2. 移动端:服务端触发的接口为 alipay.trade.wap.pay

整个流程,工作量主要在后端,前端需要做的事情比较少。

四:对接-前端代码的实现

交互流程

整个支付过程的交互流程,一共分为四步:

  1. 用户点击支付,页面新打开一个页签跳转到支付页面
  2. 用户扫码支付。
  3. 支付成功后,页面跳转回商家页面
  4. 商家页面确认是否已经交易成功,根据是否交易成功给出下一步交互。

涉及接口

由以上流程可知,整个支付流程,前端一般只会涉及到两个接口:

  1. 用户点击支付时,下订单接口,此接口会二维码的url
  2. 支付成功,跳回商家页面时候,商家查询是否支付成功的接口

代码实现

定义下单接口和查询支付结果接口

/**
 * 支付下单
 */
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>