主题
订单支付与问诊室通知(二)
本页对应 订单支付与问诊室通知,共 7 段视频,约 1 小时 4 分。
学习目标
- 能说明支付流程中用户、前端浏览器、商户后端、支付平台客户端及支付平台后台的角色分工,并指出前端主要参与“调用后端支付接口”和“引导用户支付”两个环节。
- 能根据接口文档封装支付请求方法,传入支付方式、订单 ID、支付回调地址等参数,并在用户确认支付时触发调用。
- 能根据后端返回的
payURL使用window.location.href完成 H5 支付跳转,并说明支付完成后回调地址的作用及端口配置注意事项。 - 能区分 H5 与小程序引导支付方式的差异,使用条件编译分别处理 H5 跳转和小程序支付 API 调用,并对暂不支持的微信支付给出提示。
- 能说明支付宝沙箱环境、沙箱账号及 APPID 的用途,指出支付账号与后端对接信息通常由后端申请和维护。
- 能使用原生 WebSocket 建立连接,监听
onopen、onmessage、onclose事件,调用send发送消息,并通过浏览器 Network 面板的 WS 请求验证消息收发过程。
知识点
先看支付流程图:五个角色,前端只盯两处
为什么需要:支付看起来复杂,但先分清角色,才能知道前端到底做什么。转写稿里的图要“竖着看列”:用户、浏览器、商户后台、支付平台后台、微信客户端。用户不写代码,真正配合的是浏览器、商户后台、支付平台后台、客户端等角色。
怎么想:不要一上来研究后端和支付平台怎么对接。前端只关心两处:第一步调后端接口拿结果;最后拿到地址或参数后引导用户支付。中间后端与支付平台交互,对前端可视为透明。
怎么做:按流程记:浏览器请求商户后台 → 后端对接支付平台 → 后端把结果返回前端 → 前端引导支付 → 支付完成后回跳目标页。
易错点:把“跳转支付地址”当成支付全部;忽略最终回跳页。转写稿里 payCallback 就是支付成功后回跳地址,端口要填自己的,如 5173/5174 不能写错。
调支付接口:参数、封装与 confirm 回调
为什么需要:前端要知道付多少钱、用什么方式付,必须把订单信息交给后端,由后端生成支付所需结果。
怎么想:接口是 POST,一般传支付方式、orderId、payCallback。orderId 用来确定订单和金额;payCallback 是支付成功后的回跳页。
怎么做:在 service/payment.js 封装接口,在支付组件监听到 confirm 后调用。转写稿中的关键写法如下:
js
// service/payment.js
export const orderPayment = (data) => request.post('/order/payment', data)
// 支付组件
const onPaymentFormConfirm = async (index) => {
const res = await orderPayment({
payType: index,
orderId,
payCallback: 'http://localhost:5173/pay/result'
})
console.log(res.data)
}易错点:index 要能从组件 confirm 事件解构出来;支付方式 0/1/2 的含义要按接口文档,不能猜。转写稿中微信支付暂不支持,选 0 时要提示“暂不支持微信支付”。
引导支付:网页跳 URL,小程序调 API
为什么需要:后端只返回结果,用户还需要被“引导”到支付动作。网页和小程序引导方式不同。
怎么想:H5 中后端返回 payURL,用地址跳转引导;小程序没有 window.location,要调 wx.requestPayment,参数由后端返回。
怎么做:H5 可写:
js
window.location.href = res.data.payURL小程序则调 wx.requestPayment,四个必传参数由服务端返回。转写稿还要求加条件编译:H5 才跳 URL,小程序才调支付 API;微信支付不支持时先提示。
易错点:把网页跳转硬套到小程序;忘记条件编译;payCallback 端口写错导致支付后回不到本地页面。演示中回跳页暂时空白,是因为页面内容还没补。
支付宝演示与沙箱账号
为什么需要:开发支付不能总用真钱测试,所以要理解沙箱。
怎么想:沙箱就是测试环境,里面有沙箱应用和沙箱账号,账号里有虚拟金额,只用于测试。
怎么做:演示时选支付宝,点“立即支付”后调接口,拿到 payURL 跳转;手机装了支付宝会唤起客户端,没有则可用浏览器付款。支付完成点“完成”后,会按 payCallback 回跳。
易错点:沙箱账号可能不稳定,失败可重试;不要以为沙箱余额能真实消费;应用 ID 等主要由后端对接,前端了解流程即可。
WebSocket:长连接用于持续通信
为什么需要:普通 HTTP 请求一去一回,连接结束,不适合持续聊天。WebSocket 建立连接后,浏览器和服务器可随时互发消息。
怎么想:把它想成打电话,接通后不挂断;onopen 是连接成功,onmessage 是收到服务器消息,onclose 是断开,send 是浏览器发消息。
怎么做:原生示例:
js
const ws = new WebSocket('wss://example.com')
ws.onopen = () => ws.send('测试')
ws.onmessage = (event) => console.log(event.data)
ws.onclose = () => console.log('连接断开')调试时在 Network 面板看 WS,绿色箭头是发送,红色箭头是接收。
易错点:协议是 ws/wss,不是普通 HTTP;原生写法只用于理解,实际项目会用 socket.io 这类库。
先看支付流程:前端只做“两步”
为什么需要:支付平台很多,但网页端支付的主流程基本一致。先把角色和步骤看清,写代码时就不会把后端对接支付平台的工作误当成前端任务。
怎么想:转写稿中的流程图按列表示角色:用户、浏览器、商户后台、支付平台客户端/后台。真正需要前端关心的是“浏览器—商户后台”这一段;商户后台与支付平台之间的交互对前端透明。
怎么做:前端做两件事:①调用后端支付接口;②拿到返回地址后跳转,引导用户支付。转写稿反复强调:网页端是 window.location.href 跳转;小程序端不是跳网页,而是调用支付 API 拉起支付窗口。
易错点:不要把“后端返回地址”理解成前端自己生成支付页;也不要以为整个支付都由前端完成。支付成功后回到哪个页面,由前端传给后端的回调地址决定。
封装支付接口:参数要传对
为什么需要:支付接口和普通接口一样,需要统一封装,避免页面里散落请求代码。
怎么想:转写稿中接口要求 POST,核心参数有支付方式、订单 ID、支付成功后的回调页。支付方式通常用 0/1/2 区分微信、支付宝、云闪付等;订单 ID 用于后端确定金额。
怎么做:在 service 下新建 payment.js,封装类似 orderPayment 的方法;页面点击“立即支付”时调用,并打印结果。
易错点:orderId 不是 orer IDD;payCallback 不是 pa call back;支付方式不能凭感觉写,要按接口文档。转写稿中当前后端只支持支付宝,微信支付只是参数占位。
js
// service/payment.js(按转写稿整理)
export const orderPayment = (data) => request({
url: '/order/payment',
method: 'POST',
data
})
// 页面调用
const res = await orderPayment({
payType: index, // 0 微信 1 支付宝 2 云闪付
orderId,
payCallback: 'http://localhost:5173/pay/result'
})
console.log(res.data)点击支付后跳转:拿到 payURL
为什么需要:后端与支付宝对接成功后,会把支付地址返回给前端;前端必须跳过去,用户才能付款。
怎么想:转写稿演示中,点击“立即支付”后选择支付宝,接口返回数据里有 payURL。这一步就是“引导用户支付”。
怎么做:监听支付组件的 confirm 事件,在回调里调接口;成功后执行 window.location.href = data.payURL。
易错点:回调地址端口要写自己的。转写稿里演示用 5173,若同学本地是 5174,却写死 5173,付完款就回不到自己的页面;回调页暂时空白是因为页面还没实现,不是支付失败。
js
const onConfirmPay = async () => {
const { data } = await orderPayment({
payType: index,
orderId,
payCallback: 'http://localhost:5173/pay/result'
})
window.location.href = data.payURL
}调试过程:接口成功但页面没跳
为什么需要:支付演示受测试账号、网络和本地端口影响,必须会看返回结果和网络面板。
怎么想:转写稿中出现过“接口返回成功、结果也打印了,但跳转没执行”的情况;先把地址手动粘到浏览器验证,再重走流程。还出现测试账号付款失败,刷新后恢复。
怎么做:先看 console.log(data) 是否有 payURL;再看 Network 请求是否成功;跳转不执行时检查代码位置和地址;测试账号不稳定时刷新重试。
易错点:不要看到“支付失败”就改前端逻辑,沙箱账号本身可能不稳定;也不要把本地回调地址写成别人的端口。
小程序与 H5 的“引导方式”不同
为什么需要:前面流程一样,但网页能跳 URL,小程序不能打开任意网页,也不能用 window.location。
怎么想:网页端返回 payURL 并跳转;小程序端由后端返回 wx.requestPayment 所需参数,前端调 API 拉起支付窗口。
怎么做:用条件编译区分:H5 才跳转;微信小程序才调 wx.requestPayment;当前微信支付不支持时,选微信要提示“暂不支持微信支付”。
易错点:不要把 H5 的 window.location.href 写进小程序分支;条件编译别漏,否则一端能跑、另一端报错。
js
// #ifdef H5
window.location.href = data.payURL
// #endif
// #ifdef MP-WEIXIN
wx.requestPayment({ ...data.payParams })
// #endif沙箱账号:测试支付不花真钱
为什么需要:开发支付不能每次都真付 39 元,支付宝开放平台提供沙箱环境。
怎么想:沙箱就是测试环境,有沙箱应用 ID、商户号、沙箱买家账号和虚拟余额;后端已申请好,前端只需使用后端提供的沙箱能力。
怎么做:按转写稿演示,在支付宝开放平台控制台查看沙箱账号;付款时用讲义提供的测试账号,密码按演示输入。
易错点:沙箱余额只是测试数字;应用 ID 等配置主要由后端对接,前端不要自己乱改。
WebSocket:为持续通信做准备
为什么需要:HTTP 请求通常一去一回,不适合持续聊天;WebSocket 建立连接后可随时收发消息。
怎么想:原生写法是 new WebSocket('wss://...'),连接成功触发 onopen,收到消息触发 onmessage,断开触发 onclose,发送用 send。
怎么做:转写稿用原生示例测试:打开页面看控制台“建立连接”,send 发消息,onmessage 收消息;Network 里看 WS,绿色向上是发送,红色向下是接收。
易错点:原生 WebSocket 只是理解概念,实际项目后面会用 Socket.IO 之类库;测试服务器可能不稳定,地址要确认可用。
js
const ws = new WebSocket('wss://example.com/ws')
ws.onopen = () => ws.send('测试')
ws.onmessage = (e) => console.log('收到消息', e.data)
ws.onclose = () => console.log('连接断开')支付流程先看角色和边界
为什么需要:支付不是前端单独完成的,先看清“谁和谁交互”,才不会把后端对接支付平台的工作误当成前端任务。怎么想:按流程图竖列看角色——用户、浏览器、商户后台、支付平台后台、支付客户端;真正参与开发的主要是浏览器、商户后台、支付平台后台。怎么做:前端只负责向商户后台发请求,拿到结果后引导用户支付;后端负责与支付宝/微信后台对接。易错点:把“支付成功通知”当成前端判断;把后端与支付平台交互当成前端职责。
前端只做两件事:调接口与引导支付
为什么需要:网页支付流程里,前端能控制的环节很少,抓住边界就不会乱。怎么想:流程图第2步是前端调后端接口,第4步拿返回结果,第5步引导用户支付;中间后端与支付平台的交互对前端透明。怎么做:在“立即支付”的确认事件里调用封装好的支付接口,传支付方式、订单ID、回跳地址,并打印结果。易错点:在页面加载时就调支付接口;参数名不按接口文档写;忘记处理接口失败。
js
// 示意:字段名以接口文档为准
async function onConfirmPay(index) {
const res = await paymentAPI.orderPayment({
payType: index, // 0微信 1支付宝 2云闪付(以文档为准)
orderId,
payCallback: 'http://localhost:5173/pay/result'
})
console.log(res.data)
}支付完成后的回跳与结果页
为什么需要:用户在支付宝页面付款后,要能回到自己的网站,并看到支付结果。怎么想:payCallback 就是支付成功后跳转的页面地址;本地开发要写自己的端口,5173/5174不能写错。怎么做:调接口时传回跳地址;拿到 payURL 后用 window.location.href 跳转。易错点:端口写错导致回不来;结果页还没添加所以显示空白;字段大小写写错。
js
window.location.href = res.data.payURL网页、小程序与条件编译
为什么需要:支付流程一致,但“引导用户支付”的方式不同。怎么想:网页用地址跳转;小程序没有 window.location 和 a 链接,要调 wx.requestPayment,参数由服务端返回。怎么做:H5 跳 URL,小程序调支付 API,并用条件编译隔离。易错点:把网页跳转代码放进小程序;当前后端只支持支付宝,选微信支付要提示“暂不支持微信支付”。
js
// #ifdef H5
window.location.href = res.data.payURL
// #endif
// #ifdef MP-WEIXIN
wx.requestPayment(payParams) // payParams 为服务端返回的支付参数
// #endif支付宝沙箱账号与测试
为什么需要:开发支付不能总用真钱,沙箱就是测试环境。怎么想:后端在支付宝开放平台创建应用、开通沙箱,前端拿后端配置好的沙箱账号测试。怎么做:控制台进入沙箱,查看沙箱应用和沙箱账号;测试账号有虚拟金额,支付失败可重试。易错点:沙箱金额不是真钱;沙箱账号可能不稳定;应用ID等主要是后端对接使用,前端不必自己申请。
WebSocket 为什么需要
为什么需要:HTTP 请求一次一来回,结束后连接断开,不适合持续聊天。怎么想:WebSocket 建立持久连接,像打电话不挂断,双方可随时发消息。怎么做:new WebSocket 建连接,监听 onopen、onmessage、onclose,用 send 发消息。易错点:不是所有请求都要用 WebSocket;服务器返回消息才触发 onmessage;调试看 Network 的 WS 面板,不是 XHR。
js
const ws = new WebSocket(wsUrl)
ws.onopen = () => ws.send('测试')
ws.onmessage = (e) => console.log('收到消息', e.data)
ws.onclose = () => console.log('连接关闭')WebSocket 调试与库的引入
为什么需要:原生写法帮助理解原理,但项目里直接用原生效率低。怎么想:类比 Ajax 原生 XMLHttpRequest 与 axios,WebSocket 实际开发常用 Socket.IO。怎么做:在控制台观察“建立连接”“收到消息”;Network→WS 中绿箭头是发送、红箭头是接收,连续 send 可验证持续通信。易错点:测试服务器可能延迟或不稳定;不要把原生示例当成最终项目写法;先理解概念,再引入库。
代码示例
示例一:支付接口封装 + 组件内调用(Vue3 / JS)
js
// service/payment.js —— 与支付相关的接口统一放在这里
import request from '@/utils/request'
// 订单支付
// paymentMethod: 支付方式 0-微信 1-支付宝 2-云闪付
// orderId: 订单ID(后端靠它才知道要付多少钱)
// payCallBack: 支付成功后跳回的页面地址
export const orderPayment = (data) => {
return request.post('/patient/order/payment', data)
}html
<!-- 订单详情页中,监听支付弹窗的 confirm 事件 -->
<template>
<PaymentForm @confirm="onPaymentForm" @close="showPay = false" />
</template>
<script setup>
import { ref } from 'vue'
import { orderPayment } from '@/service/payment'
const orderId = ref('') // 订单ID,从路由/详情接口里拿
const showPay = ref(false)
// 用户点了"确认支付"才会进来
// index:子组件 confirm 事件里带出来的支付方式下标
const onPaymentForm = async (index) => {
// 第二步:前端调后端接口
const { data } = await orderPayment({
paymentMethod: index,
orderId: orderId.value,
payCallBack: 'http://localhost:5173/#/payment/result'
})
// 第四步:拿到后端返回的结果
console.log(data)
// 第五步:引导用户支付 —— H5 下用地址跳转
// #ifdef H5
window.location.href = data.payURL
// #endif
}
</script>关键行与易错点
orderPayment的封装和普通接口一模一样,支付接口本身没有任何特殊性,不要把它想复杂。- 真正属于前端的只有两步:调接口(第二步)和 跳转 payURL(第五步);中间后端对接支付平台的部分前端不用管。
index来自子组件confirm事件,要记得解构出来,否则拿不到用户选的支付方式。window.location.href = data.payURL就是在“引导用户支付”,网页端靠地址跳转;小程序里没有location.href,要换成wx.requestPayment。- 易错点:
payCallBack的端口要和本地实际端口一致(5173 / 5174 要看清),写错会导致支付完回不到自己的页面。
示例二:完整可运行的 H5 支付流程演示(HTML + JS)
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>优医咨询 - 支付流程演示</title>
</head>
<body>
<h3>选择支付方式</h3>
<label><input type="radio" name="pay" value="0" /> 微信支付</label>
<label><input type="radio" name="pay" value="1" checked /> 支付宝支付</label>
<label><input type="radio" name="pay" value="2" /> 云闪付</label>
<p><button id="payBtn">立即支付</button></p>
<script>
// 模拟后端接口:真实项目中就是 service/payment.js 里的 orderPayment
function orderPayment(params) {
return new Promise((resolve) => {
setTimeout(() => {
resolve({
code: 10000,
message: 'success',
data: {
// 后端对接支付平台后返回的收银台地址
payURL: 'https://openapi.alipay.com/gateway.do?mock=1&orderId=' + params.orderId
}
})
}, 300)
})
}
const orderId = '1699999999999' // 真实项目从路由或详情接口里取
document.getElementById('payBtn').onclick = async () => {
// 取当前选中的支付方式:0 微信 / 1 支付宝 / 2 云闪付
const index = Number(document.querySelector('input[name="pay"]:checked').value)
// 当前后端只支持支付宝,微信支付先提示
if (index === 0) {
return alert('暂不支持微信支付')
}
// 第二步:调接口,传支付方式、订单ID、回跳地址
const { data } = await orderPayment({
paymentMethod: index,
orderId: orderId,
payCallBack: location.origin + '/payment-result.html'
})
// 第四步:拿结果,结果里一定有 payURL
console.log(data)
// 第五步:跳转地址,引导用户去支付
window.location.href = data.payURL
}
</script>
</body>
</html>关键行与易错点
- 整个支付前端只做两件事:
orderPayment(...)发请求、window.location.href = data.payURL跳转,其余都是后端的事。 if (index === 0) return alert('暂不支持微信支付')—— 后端目前只支持支付宝,微信必须提前拦掉,否则用户点了没反应。- 跳转后用户手机上装有支付宝会直接唤起支付宝客户端;没装则显示“继续浏览器付款”的页面,这是平台行为,前端不用处理。
- 支付成功后支付宝会跳回
payCallBack指定的地址,所以这个地址必须是自己项目里真实存在的页面(示例里对应payment-result.html),端口写错就回不来。 - 易错点:
payCallBack是支付完成后跳转的“支付结果页”,不是当前页;结果页里要做支付成功/失败的提示。
示例三:原生 WebSocket 基础用法(HTML + JS)
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>WebSocket 原生用法</title>
</head>
<body>
<button id="sendBtn">发送消息</button>
<ul id="log"></ul>
<script>
const logEl = document.getElementById('log')
const log = (msg) => {
const li = document.createElement('li')
li.textContent = msg
logEl.appendChild(li)
}
// 注意协议是 ws / wss,不是 http / https
// 这里用线上测试地址,真实项目换成后端提供的地址
const ws = new WebSocket('wss://echo.websocket.events')
// 连接建立成功
ws.onopen = () => {
log('建立连接')
ws.send('测试') // 浏览器 -> 服务器
}
// 收到服务器发来的消息(服务器每发一次就触发一次)
ws.onmessage = (event) => {
log('收到消息:' + event.data)
}
// 连接断开
ws.onclose = () => {
log('连接已断开')
}
ws.onerror = () => {
log('连接出错')
}
// 连接不断开,就可以随时发消息
document.getElementById('sendBtn').onclick = () => {
ws.send('测试呀')
}
</script>
</body>
</html>关键行与易错点
new WebSocket('ws://...')一执行,浏览器和服务器之间就“搭好了桥”,连接会一直保持,这正是和 HTTP 一次性请求最大的区别(HTTP 一次请求一次响应后就断开,做不了持续聊天)。ws.send(...)是浏览器发给服务器;ws.onmessage是服务器发回给浏览器时触发,两个方向不要搞混。- 回调里的数据在
event.data上,不是直接一个字符串。 - 协议头必须是
ws://或wss://,写成http://会直接报错;线上一般用wss。 - 调试时在浏览器 Network 面板选 WS 标签看,绿箭头是发送、红箭头是接收;这与之前看 XHR 请求的地方不一样。
- 这只是原生写法,实际项目里会用
socket.io这类库(类比:原生XMLHttpRequest之于axios)。
常见错误
1. 接口返回成功,但页面停在原地不跳转
- 现象:点"立即支付"后 Network 里接口 200,控制台也打印了结果,但页面毫无反应。
- 原因:取值的层级写错(写成
res.payURL,实际在res.data.payURL),或者跳转语句写在了await之外/错误的分支里,拿到的是undefined。 - 修法:先
console.log(res)看清结构再取字段;跳转前加一层判空if (payUrl) window.location.href = payUrl,并在失败分支给出提示。
2. 支付完成后回到空白页或 404
- 现象:支付宝里付完款点"完成",跳回来的页面一片空白。
- 原因:
payCallback抄了讲师的http://localhost:5173/...,而自己实际跑在 5174;或者目标页根本没建。 - 修法:用
location.origin动态拼回跳地址,或改成自己实际的端口;同时先把结果页建出来(哪怕只有一行文字),别让回跳地址指向不存在的路由。
3. 选了微信支付仍然发起支付请求
- 现象:下拉里选"微信支付"点确认,接口报错或跳到一个打不开的地址。
- 原因:接口约定 0/1/2 对应微信/支付宝/云闪付,但后端当前只接了支付宝;前端没做拦截。
- 修法:在 confirm 回调里先判断
index === 0→uni.showToast({ title: '暂不支持微信支付', icon: 'none' })并return,再走正常支付逻辑。
4. H5 的跳转代码跑到了小程序里(或反之)
- 现象:小程序端报
window is not defined/location is not defined,H5 端报requestPayment is not a function。 - 原因:跨端项目里直接写了平台专有 API,没有做隔离。
- 修法:用条件编译把
window.location.href = payUrl包进#ifdef H5,把uni.requestPayment({...四个参数})包进#ifdef MP-WEIXIN;两边参数都来自同一个下单接口的返回。
5. 连点"立即支付"生成多笔订单 / 多次跳转
- 现象:手抖点两下,后台出现两条订单记录,页面连跳两次。
- 原因:回调里没有防重,请求是异步的,按钮在等待期间仍可点。
- 修法:进入回调立刻置
paying = true(配合按钮:disabled或 loading),在finally里复位。
6. WebSocket 刚 new 完就 send,报 InvalidStateError
- 现象:控制台抛
Failed to execute 'send' on 'WebSocket': Still in CONNECTING state。 - 原因:连接是异步建立的,
new之后立刻send时握手还没完成。 - 修法:把首次
send放进onopen回调;或在发送前判断ws.readyState === WebSocket.OPEN。另外别把onmessage(收)和send(发)用反。
练习
练习 1|补全支付回调 在 confirm 事件的回调中:解构出 index,index === 0 时提示"暂不支持微信支付"并终止;否则调用已封装的 orderPayment,传入订单 ID、支付方式、回跳地址,成功后按平台引导用户支付(H5 跳地址 / 小程序调起支付面板)。要求代码能在 H5 与微信小程序两端都不报错。
练习 2|干掉硬编码 把 payCallback 从写死的 http://localhost:5173/#/pages/pay/result 改成运行时计算,保证换端口、换域名、打包上线都不用改代码。写出你的实现,并说明为什么不能只写 /#/pages/pay/result。
练习 3|防重复提交 给"立即支付"加上防重逻辑,要求:请求期间按钮不可再触发、请求失败后能恢复可点、控制台不出现重复请求。写出关键代码片段。
练习 4|支付结果页 新建支付结果页,onLoad 里从路由参数取出订单 ID,调用订单详情接口,根据返回的支付状态展示"支付成功 / 待支付 / 支付失败"三种文案。思考:这个页面能不能只靠 URL 参数判断成功,为什么?
练习 5|WebSocket 最小闭环 用原生 API 写一个页面:连接成功后自动发一条消息、收到消息打印到页面、断开时提示"连接已关闭",并提供一个输入框 + 按钮手动发消息。额外要求:连接未建立时点击发送不能报错。
原视频对照
| # | 视频 | 时长 |
|---|---|---|
| 1 | 优医咨询-支付流程说明 | 11:03 |
| 2 | 优医咨询-支付宝支付-1 | 09:47 |
| 3 | 优医咨询-支付宝支付-2 | 11:14 |
| 4 | 支付流程补充说明 | 08:57 |
| 5 | 支付宝支付账号管理 | 07:17 |
| 6 | websocket介绍 | 10:58 |
| 7 | websocket测试 | 05:03 |
小结
- 前端在支付链路里只负责三件事:调下单接口 → 拿结果 → 引导用户支付,中间的商户对接、签名、验签全在后端,不要越界。
- 各端支付流程完全一致,唯一的分叉点在"引导"这一步:H5 靠地址跳转,小程序靠
requestPayment传服务端给的四个参数,APP 靠 SDK。写代码时把这一层单独抽出来,后面接微信支付几乎零改动。 - 小程序端的支付参数不是前端拼的,是下单接口返回的;前端只做搬运工。
payCallback是"付完钱回到哪"的地址,必须是自己项目里真实可访问的地址,端口/域名错了就是空白页——这是最常见的坑。- 跨端项目里,凡是平台专有 API(
window.location、requestPayment)都必须用条件编译隔离,否则一端必崩。 - 商户号、APPID、沙箱账号属于后端资产;沙箱测试账号余额是假的、偶尔不稳定,遇到失败先重试或换账号,别急着怀疑自己的代码。
- WebSocket 解决的是"一次连接、双向持续通信",原生 API 只需理解
onopen / onmessage / onclose / send四件套,真实项目用 socket.io 这类库封装。 - 排错顺序固定:先
console.log看返回结构 → 再看 Network(普通接口看 XHR,长连接看 WS)→ 最后怀疑代码逻辑。