前言:node对接支付宝沙箱的心得,express,koa2都能使用。
支付宝沙箱位置在:支付宝开放平台控制台
>开发工具推荐
> 沙箱
后端部分(express/koa2)
引入alipay-sdk
npm install alipay-sdk -S
// alipay.js
const AlipaySdk = require("alipay-sdk").default;
const alipaySdk = new AlipaySdk({
// AppId
appId: "",
// 签名算法
signType: "RSA2",
// 支付宝网关
gateway: "",
// 支付宝公钥
alipayPublicKey:"",
// 应用私钥
privateKey:"",
});
module.exports = alipaySdk;
获取AppId
获取支付宝网关
- 支付宝公钥
没有的话可以选择使用系统默认秘钥生成,也可以选择自定义秘钥生成
自定义秘钥:
1)下载秘钥工具
通用工具
>支付宝开放平台秘钥工具
>秘钥工具下载
2)打开秘钥工具,生成秘钥(公钥和私钥)
3)生成支付宝公钥
将生成的秘钥中的应用公钥复制到开放平台
>沙箱应用
>接口加密方式
- 应用私钥
将生成的应用私钥格式转换
具体使用:发起支付
// router.js
// 引入支付宝配置文件
const alipaySdk = require("alipay.js存放路径");
const AlipayFormData = require('alipay-sdk/lib/form').default;
router.post('/api/payment',function(req,res,next){
//订单号
let orderId = req.body.orderId;
//商品总价
let price = req.body.price;
//购买商品的名称
let name = req.body.name;
// 开始对接支付宝API
const formData = new AlipayFormData();
//调用setMethod 并传入get,会返回可以跳转到支付页面的url,
formData.setMethod("get");
// 支付时信息
const bizContent = {
out_trade_no: orderId, //订单号
product_code: "FAST_INSTANT_TRADE_PAY",
total_amount: price, //总价格
subject: name, //商品名称
body: "商品详情", //商品描述
};
formData.addField("bizContent", bizContent);
//支付成功或失败的返回链接(前端页面)
formData.addField("returnUrl", "http://localhost:8080/payment");
// 返回promise
const result = alipaySdk.exec(
// "alipay.trade.page.pay",
"alipay.trade.wap.pay",
{},
{ formData: formData }
).catch(error => console.error('caught error!', error));
//对接支付宝成功,支付宝返回的数据
result.then((resp) => {
res.send({
data: {
code: 200,
success: true,
msg: "支付中",
paymentUrl: resp,
},
});
});
})
具体API前往官网查看
类型 | 方法 |
---|---|
pc网页支付 | alipay.trade.page.pay |
手机网站支付接口2.0 | alipay.trade.wap.pay |
统一收单交易关闭接口 | alipay.trade.close |
统一收单交易查询 | alipay.trade.query |
formData.setMethod(“get”)为返回链接,没有就是以表单形式。
发起支付后需要查看该订单支付状态,使用同一收单交易查询
// router.js
// 引入axios
const axios = require("axios");
//支付交易查询
router.post('/api/paymentQuery', function (req, res, next) {
//订单号
let out_trade_no = req.body.out_trade_no;
let trade_no = req.body.trade_no;
// 支付宝配置
const formData = new AlipayFormData();
//调用setMethod 并传入get,会返回可以跳转到支付页面的url,
formData.setMethod("get");
// 支付时信息
const bizContent = {
out_trade_no,
trade_no
};
formData.addField("bizContent", bizContent);
// 返回promise
const result = alipaySdk.exec(
"alipay.trade.query",
{},
{ formData: formData }
).catch(error => console.error('caught error!', error));
//对接支付宝API
result.then(resData => {
axios({
method: "GET",
url: resData
}).then(resdata => {
let respondeCode = resdata.data.alipay_trade_query_response;
if (respondeCode.code == 10000) {
switch (respondeCode.trade_status) {
case 'WAIT_BUYER_PAY':
res.send({
code: 10001,
message: "支付宝有交易记录,没付款"
})
break;
case 'TRADE_FINISHED':
// 完成交易的逻辑
res.send({
code: 10002,
message: "交易完成(交易结束,不可退款)"
})
break;
case 'TRADE_SUCCESS':
// 完成交易的逻辑
res.send({
code: 10002,
message: "交易完成"
})
break;
case 'TRADE_CLOSED':
// 交易关闭的逻辑
res.send({
code: 10003,
message: "交易关闭"
})
break;
}
} else if (respondeCode.code == 40004) {
return res.send({
code: 40004,
message: "交易不存在"
})
}
}).catch(err => {
return res.send({
code: 50000,
msg: "交易失败",
data: err
})
})
})
})
前端部分
// payment.vue
created() {
this.getPayData();
},
methods: {
getPayData() {
let data = {
out_trade_no: this.$route.query.out_trade_no,
trade_no: this.$route.query.trade_no,
};
axios({
url: "/api/paymentQuery",
method: "post",
Headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
// qs:增加安全性的序列化
data: qs.stringify(data),
}).then((res) => {
// 逻辑
});
},
},
运行截图
- 支付宝移动网站支付
- pc网站支付
账号密码为沙箱账号的买方信息
- 扫码支付
使用的是沙箱工具>支付宝客户端沙箱版
使用账号密码登录,账号密码为买方信息。
登录成功后可以使用扫码支付
可能遇到问题
- [Warning] page interface through formdata is deprecated. Use sdk.pageExec instead
caught error! Error: error:0D0680A8:asn1 encoding routines:asn1_check_tlen:wrong tag。
1)应用私钥没有转换格式
2)支付宝公钥/应用私钥等信息错了
- 沙箱账号没有充值按钮
解决:回退旧版本 - 支付宝客户端沙箱版无法登录
解决(我成功的例子,对于其他人可能不成功):使用uc浏览器下载。