koa实现对接支付宝沙箱支付

本文介绍了如何利用支付宝的沙箱环境进行开发者测试,包括下载密钥工具、设置沙箱应用,以及在Node.js中使用alipay-sdk进行支付链接生成和订单状态查询。通过示例代码展示了错误处理、POST请求和回调通知的配置过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、沙箱环境

支付宝有一个供开发者测试使用的沙箱环境,会提供一个沙箱版的支付宝app、一个商家账户、一个买家账户。有了这个,可以让我们跳过商家入驻、企业资质审核等过程,开箱即用,降低了学习成本。

1、密钥工具下载

密钥工具

在这里插入图片描述
在这里插入图片描述

支付宝开放平台沙箱应用
在这里插入图片描述

在这里插入图片描述

相关链接:
电脑网站支付
api文档

二、代码实现

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
注意:
如果出现下图的报错:
在这里插入图片描述
解决方案:
将应用私钥通过 支付宝开放平台密钥工具 - 格式转换菜单 进行转换
在这里插入图片描述
把生成的应用私钥放入privateKey中

  1. 安装sdk
npm install alipay-sdk
  1. alipaySdk.js文件:
const AlipaySdk = require("alipay-sdk").default; // 引入 SDK
const alipaySdk = new AlipaySdk({
  appId: "11114541", // 开放平台上创建应用时生成的 appId
  signType: "RSA2", // 签名算法,默认 RSA2
  gateway: "https://openapi.alipaydev.com/gateway.do", // 支付宝网关地址 ,沙箱环境下使用时需要修改 正式线上的时候换成 https://openapi.alipay.com/gateway.do
  alipayPublicKey:
    "MIDAQAB", // 支付宝公钥,需要对结果验签时候必填
  privateKey:
    "MIIEoUBGzxQ", // 应用私钥字符串
});
module.exports = alipaySdk;

//正式环境只要把上述换成正式的就可以了


  1. app.js文件:
//1.引入koa
const Koa = require("koa");
const axios = require("axios");
const cors = require("koa2-cors");
const static = require("koa-static");
const bodyparser = require("koa-bodyparser"); // 引入koa-bodyparser
const alipaySdk = require("./alipaySdk");

let port = 9000;
let host = "localhost";
// let host = "192.168.43.213";
const app = new Koa();

app.use(
  cors({
    // 任何地址都可以访问
    origin: "*",
    // 指定地址才可以访问
    // origin: 'http://localhost:8080',
    maxAge: 2592000,
    // 必要配置
    credentials: true,
  })
);
app.use(static("static"));


const Router = require("koa-router");
const router = new Router(); //配置无路由前缀的路由
const payMentRouter = new Router({
  //配置路由前缀为users的路由
  prefix: "/payment",
});

// 获取post提交的数据,解析请求体
app.use(bodyparser());

payMentRouter.get("/payNotify", async (ctx) => {
  console.log("payNotify====");
  ctx.body = {
    code: 0,
    msg: "成功通知",
  };
});

// 生成支付链接给用户进行支付
payMentRouter.post("/pay", async (ctx) => {
  // console.log(ctx.request.body, "ctx.request.body");
  const { orderId } = ctx.request.body;
  const AlipayFormData = require("alipay-sdk/lib/form").default;
  const formData = new AlipayFormData();
  formData.setMethod("get");
  formData.addField("bizContent", {
    outTradeNo: orderId, // 商户订单号,64个字符以内、可包含字母、数字、下划线,且不能重复
    productCode: "FAST_INSTANT_TRADE_PAY", // 销售产品码,与支付宝签约的产品码名称,仅支持FAST_INSTANT_TRADE_PAY
    totalAmount: "0.01", // 订单总金额,单位为元,精确到小数点后两位
    subject: "商品订单标题", // 订单标题
    body: "商品详情", // 订单描述
  });
  // 表示异步通知回调,必须是一个外网可以访问的网址,因为它是由支付宝服务器发起的,只能是线上访问
  // formData.addField("notifyUrl", "http://localhost:9000/payment/payNotify");
  formData.addField("notifyUrl", "https://www.baidu.com");
  // 付款成功的跳转页面
  // 可以是本地地址,因为它是本地客户端请求URL,会被本地host拦截至本地服务器中
  formData.addField("returnUrl", "http://localhost:9000/payment/payNotify");
  // const result = await alipaySdk.pageExec(
  const result = await alipaySdk.exec(
    // result 为可以跳转到支付链接的 url
    "alipay.trade.page.pay", // 统一收单下单并支付页面接口
    {}, // api 请求的参数(包含“公共请求参数”和“业务参数”)
    {
      formData: formData,
    }
  );

  ctx.body = {
    code: 0,
    msg: "成功",
    result: result,
  };
});

// 查询订单的支付状态
payMentRouter.post("/checkPayStatus", async (ctx) => {
  const { orderId } = ctx.request.body;
  let outTradeNo = orderId; // 商家订单号
  const AlipayFormData = require("alipay-sdk/lib/form").default;
  const formData = new AlipayFormData();
  formData.setMethod("get");
  formData.addField("bizContent", {
    outTradeNo,
  });
  // 通过该接口主动查询订单状态
  // 查询订单状态:https://opendocs.alipay.com/apis/api_1/alipay.trade.query?scene=23
  // 这里的result还是一个网址,我们需要axios请求这个网址,才能查看订单状态:
  let result = await alipaySdk.exec(
    "alipay.trade.query",
    {},
    {
      formData: formData,
    }
  );
  // console.log("result", result);

  try {
    const data = await axios({
      method: "GET",
      url: result,
    });
    let r = data.data.alipay_trade_query_response;
    if (r.code === "10000") {
      // 接口调用成功
      switch (r.trade_status) {
        case "WAIT_BUYER_PAY":
          ctx.body = {
            success: true,
            message: "success",
            code: 200,
            timestamp: new Date().getTime(),
            result: {
              status: 0,
              massage: "交易创建,等待买家付款",
            },
          };
          break;
        case "TRADE_CLOSED":
          ctx.body = {
            success: true,
            message: "success",
            code: 200,
            timestamp: new Date().getTime(),
            result: {
              status: 1,
              massage: "未付款交易超时关闭,或支付完成后全额退款",
            },
          };
          break;
        case "TRADE_SUCCESS":
          ctx.body = {
            success: true,
            message: "success",
            code: 200,
            timestamp: new Date().getTime(),
            result: {
              status: 2,
              massage: "交易支付成功",
            },
          };
          break;
        case "TRADE_FINISHED":
          ctx.body = {
            success: true,
            message: "success",
            code: 200,
            timestamp: new Date().getTime(),
            result: {
              status: 3,
              massage: "交易结束,不可退款",
            },
          };
          break;
      }
    } else if (r.code === "40004") {
      ctx.body = {
        code: -1,
        message: "交易不存在",
      };
    }
  } catch (err) {
    ctx.body = {
      msg: "查询失败",
      err,
    };
  }

  // ctx.body = {
  //   code: 0,
  //   result: result,
  // };
});

app.use(router.routes());
app.use(payMentRouter.routes());
app.use(payMentRouter.allowedMethods());


app.listen(port, () => {
  console.log(`http://${host}:${port}`);
});

三、启动服务并测试

  1. 命令行执行:node ./app.js 启动服务

  2. 使用postman测试接口是否正常:
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值