【jsapi支付】到底是什么?
JSAPI支付,顾名思义,是集成在浏览器环境,通过JavaScript(JS)调用支付接口实现的一种支付方式。它主要用于用户在商家网页或H5页面内购物时,调起支付平台(如微信支付、支付宝)的应用内支付能力。用户无需跳转到外部App,而是在当前浏览器(特别是移动端浏览器或App内置的Webview)环境中完成支付流程。
简单来说,当你使用手机浏览器访问一个购物网站的H5页面,点击支付按钮后,页面并没有跳出到独立的支付App,而是在当前页面内弹出了支付确认界面,输入密码或指纹即可完成支付,这就是典型的JSAPI支付体验。它依赖于支付平台在特定浏览器环境(例如微信浏览器内嵌的JSBridge,或支付宝App内嵌的H5支付能力)提供的JavaScript接口。
它通常在哪里使用?
JSAPI支付的应用场景非常广泛,尤其集中在移动互联网环境下的网页端:
- 移动端H5页面: 这是最常见的场景。用户在手机浏览器访问商家网站,通过JSAPI调起支付。
- 微信公众号内的H5页面: 在微信公众号的文章或菜单中打开的网页,可以直接利用微信浏览器环境的JSAPI支付能力。这是微信生态中非常重要的一种支付方式。
- App内置Webview: 许多原生App为了方便或展示特定内容,会在App内部嵌套一个网页视图(Webview)。如果这些网页需要支付功能,JSAPI支付是实现的好方法,用户感觉支付过程发生在App内部,体验连贯。
- 支付宝生活号内的H5页面: 类似微信公众号,支付宝生活号内的网页也支持JSAPI支付。
- 部分PC端扫码支付的后续: 虽然主要的PC端支付方式是生成二维码让用户用手机扫码(Native扫码支付),但在某些实现中,用户扫码后打开的页面可能是一个手机H5页面,此时在该H5页面内进行的支付仍然是JSAPI支付。
为什么选择JSAPI支付?
选择JSAPI支付通常是基于以下几个关键优势:
- 流畅的用户体验: 支付过程在当前浏览器环境内完成,无需应用间的切换,减少了用户的操作步骤和等待时间,显著提升支付流畅度。
- 高转化率: 由于支付流程顺畅、中断少,用户更容易完成支付,有助于提高订单转化率。
- 适用于H5/Webview场景: 它是专门为浏览器环境设计的支付方式,完美契合移动端网页购物、活动推广等场景的需求。
- 技术实现相对标准: 依赖于Web技术和支付平台提供的JS SDK,对于熟悉Web开发的团队来说,集成相对容易。
- 与社交/内容结合紧密: 在微信公众号、支付宝生活号等平台内,JSAPI支付能与内容、服务更好地结合,形成商业闭环。
JSAPI支付的整体流程是怎样的?
JSAPI支付流程涉及用户、商户的服务器和前端页面、以及支付平台。这是一个典型的“服务器端下单 + 前端调起支付 + 服务器端异步通知”模式:
- 用户发起支付请求: 用户在商户的H5页面点击支付按钮。
- 商户前端向后端提交订单信息: 包含商品信息、金额等。
- 商户后端生成预支付订单: 商户后端接收前端请求,在自己系统生成订单记录,然后调用支付平台(如微信支付、支付宝)的“统一下单”(Unified Order)API,将订单信息(金额、商品描述、商户订单号、用户的唯一标识OpenID/UserID等)发送给支付平台。这一步是服务器到服务器的通信。
-
支付平台处理下单请求: 支付平台接收并验证商户的统一下单请求,如果信息无误,会在支付平台内部生成一个预支付交易单,并返回一个“预支付交易会话标识”(如微信支付的
prepay_id)给商户后端。 -
商户后端生成前端支付参数并返回: 商户后端接收到
prepay_id后,会根据支付平台的JSAPI规范,用这个prepay_id以及其他必要参数(如AppID、时间戳、随机字符串等)再次生成签名,然后将这些签名后的参数返回给商户前端H5页面。 -
商户前端调起支付界面: 商户前端H5页面获取到后端返回的支付参数后,通过加载的支付平台JS SDK(如微信的
WeixinJSBridge),调用相应的JSAPI方法(如getBrandWCPayRequest),并将这些参数传递进去。 - 用户在支付平台界面确认支付: 支付平台的JS SDK接收到调用后,会拉起支付平台的原生支付界面(如微信支付的密码输入/指纹支付界面)。用户在此界面输入密码或确认支付。
- 支付平台处理支付结果: 支付平台完成扣款操作。
- 支付平台发送异步支付结果通知: 这是整个流程中最重要、最可靠的环节。无论用户支付成功、失败或取消,支付平台都会主动向商户在统一下单时指定的“支付结果通知URL”(Notify URL)发送一个服务器到服务器的请求,包含最终的支付结果信息。
- 商户后端处理异步通知: 商户后端接收到支付平台的通知请求,进行签名验证等安全性检查后,根据通知中的支付结果更新商户自己的订单状态(标记为支付成功、失败等)。处理成功后,需要向支付平台返回一个成功的响应,告知通知已收到并处理,避免平台重复发送。
- 支付平台JS SDK回调前端: 在用户完成支付操作(成功、失败或取消)后,支付平台的JS SDK也会通过JS回调函数通知商户前端页面操作结果。请注意: 这个前端回调仅代表用户在支付界面上的操作结果(如“支付成功”、“支付取消”),它不是最终支付结果的依据,因为网络或其他原因可能导致实际扣款失败。商户前端应根据这个回调给用户一个即时反馈(如“正在处理支付结果…”),但最终的订单状态必须以后端接收并处理的异步通知为准。
- 商户前端展示最终结果: 前端页面可以通过轮询后端或接收后端推送的方式,获取后端异步通知处理后的最终订单状态,并向用户展示确切的支付结果(支付成功页面或失败提示)。
核心要点: JSAPI支付成功与否的最终确认,必须依赖于支付平台发送给商户后端的异步通知,而不是前端JS回调。
如何进行JSAPI支付的开发集成?
JSAPI支付的开发集成主要分为准备工作和后端开发、前端开发几个步骤。
准备工作:
- 申请支付能力: 确保你的商户账号已在支付平台(如微信支付商户平台、支付宝商户平台)开通了JSAPI支付(或对应的H5支付)能力。
- 配置安全域名: 在支付商户平台的相应位置配置允许调用JSAPI的域名(通常是你的H5页面的域名),这一步是为了防止JSAPI被非法网站调用。
- 获取API密钥和证书: 获得支付平台的商户号(MchID)、AppID(与公众号/小程序/App关联的ID)、API密钥(用于签名)以及可能需要的API证书。
- 设置支付结果通知URL: 在商户平台或通过API设置接收支付结果异步通知的URL,这个URL必须是公网可访问的,且能稳定接收POST请求。
后端开发(以微信支付为例):
后端主要负责处理支付逻辑、与支付平台API通信、处理异步通知等。
- 接收前端支付请求: 接口接收前端传来的订单必要信息(如商品ID、数量、用户ID等)。
- 获取用户OpenID: 对于微信JSAPI支付,必须知道支付用户的OpenID。如果用户是通过微信公众号或小程序进入H5的,可以通过微信OAuth授权流程获取。如果用户是直接在微信浏览器中访问H5,通常可以自动获取。需要一套获取OpenID的机制。
-
调用“统一下单”API:
- 构建请求参数:包括
appid,mch_id,nonce_str,body(商品描述),out_trade_no(商户内部订单号),total_fee(订单总金额,单位是分),spbill_create_ip(用户终端IP),notify_url(支付结果通知URL),trade_type(设置为JSAPI),openid(用户的OpenID)。 - 生成签名:将上述参数按照规则排序、拼接,使用API密钥进行签名(通常是MD5或HMAC-SHA256),将签名结果作为
sign参数加入请求中。 - 发送POST请求到支付平台的统一下单接口URL。
- 构建请求参数:包括
-
处理统一下单响应:
- 验证响应的签名。
- 检查通信状态和业务结果码。
- 如果下单成功,解析响应,提取
prepay_id。
-
生成前端JSAPI调起支付所需参数:
- 根据支付平台JSAPI规范,构建前端需要的参数集,例如:
appId,timeStamp,nonceStr,package(值为'prepay_id=' + prepay_id),signType(签名算法,如’MD5’或’RSA’),paySign(用这些参数再次签名)。 - 将这些参数返回给前端页面。
- 根据支付平台JSAPI规范,构建前端需要的参数集,例如:
-
实现支付结果异步通知接口:
- 这是一个独立的URL接口,用于接收支付平台发来的POST通知。
- 接收到通知后,首先验证请求是否来自支付平台(通过IP白名单、签名验证等)。
- 解析通知内容,检查支付状态(例如,微信支付通知中的
result_code和return_code是否都为SUCCESS)。 - 重点: 根据通知中的商户订单号(
out_trade_no)查找内部订单,比对支付金额(total_fee)是否一致,防止篡改。 - 如果支付成功且信息无误,更新内部订单状态为“已支付”,处理后续业务逻辑(如发货、提供服务)。注意要保证幂等性,避免重复处理。
- 处理成功后,返回一个符合支付平台要求的响应(例如,微信支付要求返回XML格式的
<return_code>SUCCESS</return_code><return_msg>OK</return_msg>)。处理失败也要返回相应错误码。
前端开发:
前端主要负责页面展示、调用后端接口获取支付参数、通过JS SDK调起支付界面、处理JS回调。
-
加载支付平台JS SDK: 在H5页面中通过
<script>标签引入支付平台提供的JS SDK文件。例如,微信支付JS-SDK。 -
等待页面和SDK加载完成: 确保DOM加载完毕且支付JS SDK的核心对象(如
WeixinJSBridge)可用。对于微信,通常监听WeixinJSBridgeReady事件。 - 调用后端接口获取支付参数: 在用户点击支付按钮后,通过Ajax或Fetch等方式调用商户后端提供的接口,获取在后端签名好的前端支付参数。
-
调起支付界面: 在获取到参数后,调用支付平台JS SDK提供的支付接口,将后端返回的参数传递进去。例如,微信支付调用
WeixinJSBridge.invoke('getBrandWCPayRequest', {...params...}, function(res){...});。 -
处理JS回调: 在JS回调函数中,可以获得用户在支付界面操作的结果。
- 例如,微信支付的
res.err_msg可能是"get_brand_wcpay_request:ok"(用户完成支付操作)、"get_brand_wcpay_request:cancel"(用户取消支付)、"get_brand_wcpay_request:fail"(支付失败,通常伴随错误码)。 - 再次强调: 这个回调结果仅代表用户操作,不能作为最终支付成功的依据。
- 根据回调结果,给用户友好的提示,例如“支付处理中”、“支付已取消”。对于“支付成功”的提示,最好引导用户查看订单状态页或通过其他方式确认最终结果。
- 例如,微信支付的
- 展示最终支付结果: 页面应有机制(如跳转到订单详情页,或在当前页查询后端订单状态)来向用户展示基于后端异步通知确认的最终支付结果。
开发过程中需要注意哪些细节?
安全性是重中之重:
- 签名验证: 无论是调用统一下单API,还是接收支付平台的异步通知,都必须严格进行签名生成和验证,确保数据未被篡改。
-
异步通知处理:
- 幂等性: 异步通知可能会重复发送,后端处理程序必须确保同一笔订单号的通知只被有效处理一次。可以通过记录已处理的通知ID或在更新订单状态前检查当前状态来实现。
- 重要信息比对: 接收到通知后,务必比对通知中的订单金额和商户订单号与自己系统中的记录是否一致,这是防止伪造通知的关键一步。
- 及时响应: 成功处理通知后,务必按照平台要求返回成功响应,否则平台会认为通知失败并进行重试,增加服务器压力。
- 不要依赖前端结果: 任何重要的业务逻辑(如订单状态更新、发货、积分发放)都必须基于后端接收并验证的异步通知,不能依赖前端JS回调。
- HTTPS: 你的支付结果通知URL必须支持HTTPS,保证数据传输安全。调用支付平台API时也通常使用HTTPS。
- IP白名单: 在商户平台配置允许访问你的通知URL的支付平台服务器IP地址范围,增加安全性。
用户体验与容错:
- 前端反馈: 在用户点击支付后,到支付界面弹出前,给用户一个“正在加载”或“正在调起支付”的提示,避免用户误以为没反应而重复点击。
- 处理取消和失败: 用户可能会取消支付或支付失败,前端JS回调会反映这个结果。提供清晰的提示,并引导用户可以重新尝试支付或选择其他支付方式。
- 网络异常: 考虑用户网络不好导致JS SDK加载失败、调起支付慢、通知丢失(虽然平台会重试,但商户端也要有对账机制)等情况。
技术细节:
- 金额单位: 支付平台的金额通常以“分”为单位,后端在处理金额时务必注意单位转换。
- OpenID获取: 对于微信JSAPI,OpenID是必需的参数,需要提前设计好获取OpenID的流程,可能需要用户授权。
- 对账: 定期与支付平台进行对账,核对交易记录,确保所有成功支付的订单都已正确处理,发现异常及时处理。
使用JSAPI支付会有多少费用?
使用JSAPI支付的费用主要构成如下:
- 交易手续费: 这是主要的费用。支付平台会根据每笔交易的金额按照一定的费率收取手续费。这个费率不是固定的,取决于商户的行业类型、交易量、与支付平台协商的协议等因素,通常在0.3%到1%之间,有些特定行业(如公益)可能有优惠费率。例如,一笔100元的交易,如果费率是0.6%,则手续费是0.6元。
- 开发集成费用: 这是一次性的投入,取决于你的开发团队的工作量和时间成本。实现JSAPI支付的后端接口、前端调用、异步通知处理、订单状态更新等都需要开发和测试时间。
- 维护和运营费用: 包括服务器费用、网络费用、对账和异常处理的人力成本等。
需要明确的是,支付平台通常不会对JSAPI接口本身的调用次数收费,费用主要体现在成功的交易笔数和金额上。在申请开通支付能力时,支付平台会明确告知适用的交易费率。