路虽远 行则将至

Lee


  • 主页
  • 归档
  • 分类
  • 标签
  •   

站点访客数   人

站点浏览量   次

本页浏览量   次

© 2024 辣辣辣白菜

Theme Typography by Makito

Proudly published with Hexo

(JS)NodeJS+微信小程序接入支付宝支付沙箱

Posted at 2024-03-09 Coding  NodeJS 小程序 

前言

支付宝和微信现在都有提供沙箱支付系统,供开发人员测试支付功能使用;但微信的沙箱需要商家资质,对于个人开发者很不友好。鉴于在微信小程序中只是单纯为了实现支付流程,决定采用支付宝的沙箱系统。缺点是用户必须复制支付链接后在浏览器打开进行支付,再返回小程序确认支付状态。

订单支付的工作流程

image-20240310010026110

用户从购物车选好物品后,点击 去结算 按钮,小程序请求服务端创建订单,此时会服务端生成一个订单号(本例中使用毫秒级时间戳代替)作为该订单的标识,并将订单信息返回给小程序。

然后用户在结算页面,点击确认支付后,小程序携带订单号和总金额请求服务端 /api/pre/set/order/state 接口,服务端调用AlipaySDK 的 alipay.trade.page.pay 接口,生成一个订单支付链接,如:

https://openapi-sandbox.dl.alipaydev.com/gateway.do?method=alipay.trade.page.pay&app_id=XXXXXXX&charset=utf-8&version=1.0&sign_type=RSA2&timestamp=2024-03-09%2022%3A03%3A12&return_url=XXX&sign=XXXXXXXXXXXXXXXXXymqag%3D%3D&alipay_sdk=alipay-sdk-nodejs-3.6.1&biz_content=%7B%22out_trade_no%22%3A%XXXX%22%2C%22product_code%22%3A%22FAST_INSTANT_TRADE_PAY%22%2C%22total_amount%22%3A1088%2C%22subject%22%22%7D

此时服务端将此链接返回给小程序,提示用户复制链接到浏览器打开并支付即可。

当用户点击复制按钮后,程序自动将该链接复制到用户手机的剪贴板上,此时界面停留在 “确认我已支付” 界面,待用户在浏览器支付完成并返回小程序,点击 “我已支付” 按钮时,小程序携带订单号请求服务端 /api/pre/get/pay/state 接口,服务端调用 AlipaySDK 的 alipay.trade.query 接口,同样会返回一个查询订单状态的链接,我们在服务端直接使用 GET 请求该链接,返回内容即为目标订单状态。

状态码 状态 含义
10001 WAIT_BUYER_PAY 支付宝有交易记录,没付款
10002 TRADE_FINISHED 交易完成(交易结束,不可退款)
10002 TRADE_SUCCESS 交易完成
10003 TRADE_CLOSED 交易关闭

环境准备

首先需要登录 https://open.alipay.com/develop/sandbox/app 注册一个沙箱应用,并拿到沙箱的AppID、支付宝公钥、应用私钥:

image-20240310012620490

然后在后端项目安装 alipay-sdk 和 axios

npm install alipay-sdk -S
npm install axios -S

后端接入

封装alipay.js

const AlipaySdk = require("alipay-sdk").default;
const alipaySdk = new AlipaySdk({
    // AppId
    appId: "XXXXXXX",
    // 签名算法
    signType: "RSA2",
    // 支付宝网关
    gateway: "https://openapi-sandbox.dl.alipaydev.com/gateway.do",
    // 支付宝公钥
    alipayPublicKey: "XXXXXXXXXXXXXXXXXXXX",
    // 应用私钥
    privateKey: "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
});
module.exports = alipaySdk;

生成支付链接

const goodsName = req.body.goodsName   // 订单标题
const totalPrice = req.body.price      // 订单总价
const formData = new AlipayFormData();
formData.addField("bizContent", {
  outTradeNo: orderNumber, // 订单号
  productCode: "FAST_INSTANT_TRADE_PAY",
  totalAmount: totalPrice, // 订单总价
  subject: goodsName,      // 订单名称
  body: goodsName,         // 订单描述
});
formData.addField("returnUrl", "http://localhost:3303/api/back/payment");
formData.setMethod("get");
// 返回promise
const result = await alipaySdk.exec('alipay.trade.page.pay', // alipay.trade.wap.pay 为手机端接口
  {}, // api 请求的参数(包含“公共请求参数”和“业务参数”)
  { formData: formData },
);
res.send({
  code: 200,
  success: true,
  msg: "支付中",
  paymentUrl: result, // result为用户需要打开的支付链接
});

查询支付结果

const { orderNumber } = req.body
const formData = new AlipayFormData();
formData.setMethod("get");
formData.addField("bizContent", { outTradeNo: orderNumber });
const result = alipaySdk.exec("alipay.trade.query",{},{ formData: formData }).catch(error=>console.error('caught error!', error));
result.then(resData => {
axios({
  method: "GET",
  url: resData
}).then(e => {
  let code = e.data.alipay_trade_query_response;
  if (code.code == 10000) {
    switch (code.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;
    }
    // 订单已支付 更新订单状态
    if (code.trade_status === "TRADE_FINISHED" || code.trade_status === "TRADE_SUCCESS") {
      // 更新订单状态(执行SQL)
    }
  } else if (code.code == 40004) {
    return res.send({
      code: 40004,
      message: "交易不存在"
    })
  }
}).catch(err => {
  console.log(err);
  return res.send({
    code: 50000,
    msg: "交易失败",
    data: err
  })
})
})

공유하기 

 이전 포스트: 记一次阿里云物联网MQTT的调试过程 다음 포스트: (C#)使用SolidWorks API模板开发SolidWorks插件 

站点访客数   人

站点浏览量   次

本页浏览量   次

© 2024 辣辣辣白菜

Theme Typography by Makito

Proudly published with Hexo