前端接入Paymax支付请求
材料指南
-
开发者平台 :配置开发必备信息(appid,商户号,公钥私钥),此处与请求参数
appId
、merchantNo
有关。 -
PayerMax Apis:各支付接口信息,本文以收银台支付API为请求展开,请求url为
orderAndPay
,测试环境基础路径为:https://pay-gate-uat.payermax.com /aggregate-pay/api/gateway
-
PayerMax接口说明:HTTPS传输 + POST方法提交 + 签名算法(SHA256WithRSA) + 接口结构 + 测试/生产环境地址 + 接口列表(收银台支付/纯API支付)
-
国家币种支持:不同国家支付渠道支持的币种,比如USD(美元)、IDR(印度尼西亚比盾)、PHP(菲律宾比索),此处与请求参数
currency
和country
有关。 -
各国支付方式处理:比如印度只支持Card类支付(Vsia、MasterCard),印尼支持APM方式支付,OTC、 BANK_TRANSFER(当地银行卡转账)、WALLET(钱包)等多种支付,此处与请求参数
paymentDetail
有关。
操作步骤
1.生成私钥(PrivateKey)和公钥(PublicKey)
通过加入开发者平台,点击左侧菜单栏-开发者工具-rsa密钥生成,点击按钮Generate Key Pair
生成私钥匙PrivateKey
和公钥publicKey
,需要自己保存好,下一步需要用到。
2.上传公钥
点击菜单栏左侧-基础设置-开发信息,点击按钮公钥上传,将第一步的公钥复制到商户公钥内,点击确定按钮。
复制保留商户号,Appid,商户公钥信息,发起请求需要用到。
3.模拟请求
此处以收银台支付-下单api为例(orderAndPay)
请求参数基础配置,更多data内参数配置,查看顶部PayerMax Apis对应接口的参数配置和返回数据设置。
{
"version": "1.1",
"keyVersion": "1",
"requestTime": "{{requestTime}}",//(*)请求时间:ISO 格式当前时间的时间戳
"appId": "{{appId}}",//(*)appid
"merchantNo": "{{merchantNo}}",//(*)商户号
"data": {
"integrate": "Hosted_Checkout", // (*)集成类型
"outTradeNo": "{{orderNumber}}",//订单编号唯一,否则请求失败
"subject": "111",//订单标题名称
"totalAmount": "11",//金额
"currency": "IDR",//金额单位(对应国家简称,比如国家为ID,支持金额为IDR,或USD)
"country": "ID",//国家简称
"userId": "167688058870154999",//用户编号唯一,否则请求失败
"language": 'en', // 默认语言
"paymentDetail": {
"paymentMethod": "",//支付方式
"targetOrg": ""//目标组织
},
"frontCallbackURL": "https://www.baidu.com",// 前端回调 URL
"notifyUrl": "https://www.baidu.com"// 后端通知 URL
}
}
完整模拟测试:
模拟请求(可以根据我的这个请求设置做相应修改):
{
"version": "1.1",
"keyVersion": "1",
"requestTime": "{{requestTime}}",
"appId": "{{appId}}",
"merchantNo": "{{merchantNo}}",
"data": {
"integrate": "Hosted_Checkout",
"outTradeNo": "ORD1542659689",
"subject": "测试支付",
"totalAmount": "11",
"currency": "USD",
"country": "BR",
"userId": "167688058870154999",
"paymentDetail": {
"paymentMethod": "CARD",//CARD为visa和mastercard支付
"targetOrg": ""//paymentMethod对应信息,其中paymentMethod为CARD,targetOrg为空。对应支付方式看顶部paymentDetail配置链接或文档
},
"frontCallbackURL": "https://www.baidu.com",
"notifyUrl": "https://www.baidu.com"
}
}
响应数据内容(http结构输入框内的数据):
POST https://pay-gate-uat.payermax.com/aggregate-pay/api/gateway/orderAndPay
content-type: application/json
sign: X93Cp******超级长的字符串******ZweJ8y50Iw==
{"version":"1.1","keyVersion":"1","requestTime":"2024-11-18T08:20:35.411Z","appId":"你的appid信息","merchantNo":"你的商户号","data":{"integrate":"Hosted_Checkout","outTradeNo":"ORD1542659689","subject":"测试支付","totalAmount":"11","currency":"USD","country":"BR","userId":"167688058870154999","paymentDetail":{"paymentMethod":"CARD","targetOrg":""},"frontCallbackURL":"https://www.baidu.com","notifyUrl":"https://www.baidu.com"}}
content-type: application/json
sign: N+K3//5RSOnm******超级长的字符串******tUCTtXGQ==
{"msg":"Success.","code":"APPLY_SUCCESS","data":{"redirectUrl":"https://cashier-n-uat.payermax.com/v2/index.html#/payments?merchantId=*********d&merchantAppId=*******&country=BR&tradeToken=T2********8&paymentMode=CARD&language=pt&token=63************8&amount=11¤cy=USD&version=1.1&cashierId=T202411******&frontCallbackUrl=https%3A%2F%2Fwww.baidu.com&pmaxLinkV=1","outTradeNo":"ORD1542659689","tradeToken":"*********","status":"PENDING"}}
4. 前端请求实操
安装axios:
npm install axios
安装 jsrsasign 库,此处是对 privateKey 对请求数据进行 RSA 加签:
npm install jsrsasign
前端请求封装:
新建utils文件夹,目录下新建request.js
import axios from 'axios';
// 配置基础请求的 URL
const BASE_URL = 'https://pay-gate-uat.payermax.com/aggregate-pay/api/gateway/';
import * as jsrsasign from 'jsrsasign';
// 测试环境
const merchantNo = '**********';// 你的商户号
const appid = '***********';// 你的appid
const privateKey = `-----BEGIN PRIVATE KEY-----
*****你的超长私钥****
-----END PRIVATE KEY-----`;
// 创建通用的 axios 请求函数
const sendPaymaxRequest = async (endpoint, paymaxParam) => {
// 构造请求体
const data = {
version: '1.1',
keyVersion: '1',
requestTime: paymaxParam.requestTime, // 客户端传入的请求时间
appId: appid, // 固定的 appId
merchantNo: merchantNo, // 固定的 merchantNo
data: {
outTradeNo: paymaxParam.outTradeNo, // 唯一订单号
subject: paymaxParam.subject, // 标题
totalAmount: paymaxParam.totalAmount, // 总金额
currency: paymaxParam.currency, // 货币单位
country: paymaxParam.country, // 国家
userId: paymaxParam.userId, // 用户 ID
language: 'en', // 默认语言
reference: 'reference查询和回调返回', // 可自定义
frontCallbackUrl: 'http://www.baidu.com', // 前端回调 URL
notifyUrl: 'http://www.notifyUrl.com', // 后端通知 URL
integrate: 'Hosted_Checkout', // 集成类型
expireTime: '1800', // 过期时间(单位:秒)
paymentDetail: {
paymentMethodType: paymaxParam.paymentMethod, // 支付方式
targetOrg: paymaxParam.targetOrg, // 目标组织
},
},
};
// 对请求体进行签名
const sign = generateSign(data);
// 设置请求头
const headers = {
sign: sign, // 签名
'Content-Type': 'application/json', // 设置请求头 Content-Type
Accept: 'application/json', // 接受返回 JSON 数据
};
try {
// 使用 axios 发送请求,拼接不同的接口
const response = await axios.post(`${BASE_URL}${endpoint}`, data, { headers });
return response.data; // 返回接口响应数据
} catch (error) {
console.error('请求失败:', error);
throw error; // 错误抛出
}
};
// 生成RSA签名的函数
const generateSign = (data) => {
// 将请求体数据转换为JSON字符串
const jsonString = JSON.stringify(data);
// 创建 RSA 私钥对象
const rsaKey = jsrsasign.KEYUTIL.getKey(privateKey);
// 创建一个签名对象,指定使用的算法
const signature = new jsrsasign.KJUR.crypto.Signature({ "alg": "SHA256withRSA" });
signature.init(rsaKey);
signature.updateString(jsonString);
// 对请求体数据进行签名,返回 Base64 编码的签名
const signed = signature.sign();
console.log(jsrsasign.hextob64(signed))
return jsrsasign.hextob64(signed); // 返回 Base64 编码的签名
};
export default sendPaymaxRequest;
页面请求:
<script>
import sendPaymaxRequest from '../../utils/request.js'
export default {
data() {
return {
paymaxParam:{
requestTime:'',//当地时间搓
outTradeNo:'',//唯一订单号
subject:'',//标题名称
totalAmount:'',
currency:'',//货币单位,USD
country:'',
userId:'',
paymentMethod:'',
targetOrg:''
}
}
},
created(){
},
methods: {
getRecharge(){
// 获取当前时间的 Date 对象
const now = new Date();
// 转换为 ISO 格式字符串(包括时区信息)
const isoString = now.toISOString();
console.log("ISO String:", isoString);
// 随机订单编号
const generateOrderId = () => {
const prefix = "ORD"; // 订单前缀,可自定义
const timestamp = Date.now().toString(); // 时间戳
const randomNumber = Math.floor(Math.random() * 10000); // 随机 4 位数
return `${prefix}${timestamp}${randomNumber}`;
}
// 随机用户 ID
const generateUserId = () => {
const prefix = "USER"; // 用户 ID 前缀
const timestamp = Date.now().toString().slice(-5); // 时间戳后 5 位
const randomNumber = Math.floor(Math.random() * 1000); // 随机 3 位数
return `${prefix}${timestamp}${randomNumber}`;
}
// 随机订单编号
const orderId = generateOrderId()
// 随机用户id
const userId = generateUserId()
const paymaxParam = {
requestTime: isoString,
outTradeNo: orderId,
subject: this.paymaxParam.paymentMethod + this.paymaxParam.targetOrg +'支付',
totalAmount: this.paymaxParam.totalAmount,
currency: 'USD',
country: this.paymaxParam.country,
userId: userId,
paymentMethod: this.paymaxParam.paymentMethod, // 假设这是支付方式
targetOrg: this.paymaxParam.targetOrg, // 目标组织
};
// 调用发送请求的函数
sendPaymaxRequest('orderAndPay', paymaxParam)
.then(response => {
console.log('OrderAndPay 请求成功:', response);
const redirectUrl = response.data.redirectUrl
console.log(redirectUrl);//确保每次提交的参数,orderId 每次都不一样,否则测试环境下即使请求成功,也不会返回response.data.redirectUrl(没有支付页面跳转)值为undefined.
// 判断平台进行跳转
if (process.env.UNI_PLATFORM === 'h5') {
// 在H5环境下
window.location.href = redirectUrl;
} else if (process.env.UNI_PLATFORM === 'app-plus') {
// 在 App 环境下
if (typeof plus !== 'undefined' && plus.runtime) {
plus.runtime.openURL(redirectUrl);
} else {
console.warn("当前环境不支持 openURL 跳转");
}
} else if (process.env.UNI_PLATFORM === 'mp-weixin') {
// 在微信小程序环境下,外部链接需要用 web-view 组件打开
uni.navigateTo({
url: `/pages/webview/webview?redirectUrl=${encodeURIComponent(redirectUrl)}`
});
} else {
console.error('不支持的运行平台');
}
})
.catch(error => {
console.error('请求失败:', error);
});
}
}
}
</script>
根据对应的redirectUrl跳转到不同的支付平台
5.订单信息查询
每一笔订单信息,即使请求成功或者失败,都会保存在
菜单栏-交易信息-订单列表中
注意点
1.sign签名的处理
- sign是通过私钥进行rsa加签生成,请求体同请求接口参数格式一样,请求体body的数据有无进行格式化,生成的sign是不一样的。要使完整请求成功,请求体格式应该相同。
详细看官方文档此处:PayerMax配置与签名
- 通过rsa加签私钥会把body的请求数据加入处理,所以请求要保持请求体body数据格式一致。
- sign正确格式尾部应为
==
结尾 - 前端js请求头部设置:
// 设置请求头
const headers = {
sign: sign, // 签名
'Content-Type': 'application/json', // 设置请求头 Content-Type
Accept: 'application/json', // 接受返回 JSON 数据
};
2.国家和币种处理
- 此处与请求参数
currency(特价币种)
、country(国家代码)
、totalAmount(标价金额)
相关。 比如:
巴西的国家代码为BR,支持的特价币种为BRL和USD俩种,支持方式为APM、CARD、APPLEPAY、GOOGLEPAY
使用对应支付,支付金额不能小于对应标准,比如选用USD作为特价币种,选择苹果支付时,totalAmount
不能小于0.01,以此类推。
- 正常情况可以使用USD美元作为支持的特价币种,paymax可以自动转换当地支付方式的比例。
3.支付方式配置及注意事项
- 前端配置数据参考(结合个人项目实际,这里仅作参考):
const data = [
{ country:'BR',
ename:'Brazil',
cname:'巴西',
methods:[
{icon:'',way:'Card',rname:'Credit Card',paymentMethodType:'CARD',targetOrg:''},
{icon:'',way:'APM',rname:'Bank Transfer',paymentMethodType:'BANK_TRANSFER',targetOrg:''},
{icon:'',way:'APM',rname:'PIX',paymentMethodType:'REALTIME_PAYMENT',targetOrg:'PIX'},
{icon:'',way:'APM',rname:'Boleto',paymentMethodType:'OTC',targetOrg:'BOLETO'},
{icon:'',way:'APM',rname:'Boleto fast',paymentMethodType:'OTC',targetOrg:'BOLETO_FAST'},
{icon:'',way:'APM',rname:'MercadoPago',paymentMethodType:'WALLET',targetOrg:'MERCADOPAGO'},
{icon:'',way:'APM',rname:'PicPay',paymentMethodType:'WALLET',targetOrg:'PICPAY'},
{icon:'',way:'GOOGLEPAY',rname:'Google Pay',paymentMethodType:'GOOGLEPAY',targetOrg:''},
{icon:'',way:'APPLEPAY',rname:'Apple Pay',paymentMethodType:'APPLEPAY',targetOrg:''}
],
unit:['USD','BRL']},{..其他国家...}
]
-
其中苹果支付(APPLEPAY)、谷歌支付(GOOGLEPAY)的
paymentDetail
参数设置,当支付方式类型为APPLEPAY时,目标对应机构为空。类似的还有CARD支付方式类型,还有此类卡(VISA、MasterCard)。参数设置为paymentMethodType:'APPLEPAY',targetOrg:''
,其中苹果支付成功后跳转浏览器只支持safari浏览器上,其他设备或浏览器请求将无法显示ApplePay支付选项。 -
其他支付方式需上传对应的支付方式类型和目标机构,比如
paymentMethodType:'WALLET',targetOrg:'NUPAY'
4.虚拟Visa、MasterCard测试数据
虚拟账号,仅用于测试使用
原文地址:https://blog.csdn.net/m0_47814717/article/details/143858507
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!