React+Redux+Ant Design+TypeScript 电子商务实战-服务端应用 05 支付宝SDK & pm2

本文详细介绍了如何集成支付宝SDK,包括配置沙箱环境、生成和保存密钥、创建支付流程及验签。内容涵盖了从获取支付地址、处理同步跳转和异步通知到数据库操作的全过程,适合开发者参考。

支付宝开发工具介绍

工具介绍

alipay-sdk

alipay-sdk 是支付宝 NodeJS 版 的 服务端 SDK (通用版),用于实现本例的支付功能。

配置沙箱环境应用的密钥

沙箱环境默认有一个用于测试的应用,代码编写时使用它的 APPID。

首次使用该应用还是需要配置密钥,生成密钥参考:生成密钥并上传

本例使用 “Web 在线加密” 生成密钥,这是网页版工具不需要下载。

  • 密钥长度(即签名算法)选择默认推荐的 RSA2
  • 密钥格式选择 PKCS2(非JAVA适用)

生成密钥会生成应用私钥应用公钥两个字符串,记得将它们保存到本地。

设置沙箱环境应用的密钥时:

  • 密钥的加签方式是“公钥”
  • 将刚才生成的应用公钥配置进去,保存设置后会生成支付宝公钥,记得将其保存到本地

保存到本地的目的:

由于实例化 SDK 客户端时需要指定应用的私钥信息,请务必注意不要将私钥信息配置在源码中(比如配置为常量或储存在配置文件的某个字段中等),因为私钥的保密等级往往比源码高得多,将会增加私钥泄露的风险。推荐将私钥信息储存在专用的私钥文件中,将私钥文件通过安全的流程分发到服务器的安全储存区域上,仅供自己的应用运行时读取。

来源:Alipay SDK 集成说明

保存到项目 /pem 目录下的文件:

  • app_public_key.txt - 应用公钥
  • app_private_key.txt - 应用私钥
  • alipay_pubilic_key.txt - 支付宝公钥

使用 OpenSLL 工具生成的密钥是 pem 格式的,使用“Web 在线加密”工具生成的是字符串或 txt 文本格式的密钥,所以本例全部以 .txt 文件保存。

支付流程

本例支付流程没有指南中那么严谨:

  1. 系统在支付订单前并不向数据库保存订单数据
  2. 用户在商户订单页面点击支付按钮
  3. 客户端向服务器发送请求获取到PC端支付宝收银台地址后跳转
  4. 用户在收银台地址登录并完成支付后,进行两个操作:
    1. 同步跳转回商户网站的支付成功页面
    2. 异步向商户发送通知(请求商户提供的 api)
  5. 商户接收到异步通知,对请求进行验签,确认来源安全后创建订单保存到数据库

创建 SDK 实例并配置 api

配置 SDK 时部分字段需配置为沙箱环境指南中指定的值。

验签:指的是交易成功后反向发送请求时验证请求来源,防止伪造请求。

// controllers\alipay.js
const AlipaySdk = require('alipay-sdk').default
const fs = require('fs')
const path = require('path')

// APPID
const appId = '2021000118602014'

// alipay-sdk 配置选项
const alipaySdkConfig = {
   
   
  // 应用id
  appId,
  // 应用私钥字符串
  privateKey: fs.readFileSync(path.join(__dirname, '../pem/app_private_key.txt'), 'ascii'),
  // 签名算法
  signType: 'RSA2',
  // 支付宝公钥(需要对返回值做验签时候必填)
  alipayPublicKey: fs.readFileSync(path.join(__dirname, '../pem/alipay_public_key.txt'), 'ascii'),
  // 网关地址
  gateway: 'https://openapi.alipaydev.com/gateway.do',
  // 网关超时时间
  timeout: 5000,
  // 是否将网关返回的下划线 key 转换为驼峰写法
  camelcase: true
}

// 获取支付地址
const getPayUrl = async (req, res) => {
   
   
  // 获取订单信息
  // totalAmount 订单总金额
  // subject 订单标题
  // body 订单描述
  // products 产品列表
  // address 收货地址
  // userId 用户id
  const {
   
    totalAmount, subject, body, products, address, userId } = req.body

  // 创建 SDK 实例
  const alipaySdk = new AlipaySdk(alipaySdkConfig)

  res.send('OK')
}

module.exports = {
   
   
  getPayUrl
}

执行请求接口使用

接口介绍

/**
 * 执行请求
 * @param {string} method 调用的 api 名称
 * @param {object} params [可选] api 请求参数,包含公共请求参数和业务参数
 * @param {object} params.bizContent 业务请求参数
 * @param {Boolean} option [可选] 选项
 * @param {Boolean} option.validateSign [可选] 是否对返回值验签
 * @param {object} option.formData [可选] 页面类接口请求参数
 * @param {object} option.log [可选] 日志记录对象,对象需包含两个记录日志的方法{info, error}
 * @return {Promise} 请求执行结果
 */
exec(method: string, params?: IRequestParams, option?: IRequestOption): Promise<AlipaySdkCommonResult | string>;

请求参数

关于请求参数 params,需要参考接口文档,例如本例使用的电脑网站支付接口:alipay.trade.page.pay(统一收单下单并支付页面接口),该接口用于返回 PC 端的支付宝收银台地址

传递请求参数的时候可以使用驼峰写法。

文档中的请求参数包含两个部分:

  • 公共参数-公共请求参数
    • 规定在 params 对象中传递的参数
    • 默认会使用 SDK 配置对象中的参数,也可以重新指定
  • 请求参数(biz_content)-业务参数
    • 规定在 params.biz_content 对象中传递的参数
    • 只有当公共请求参数列表中包含 biz_content时,才需要传递这个对象

页面类接口

页面类接口默认返回的数据为 html 代码片段(如 alipay.trade.page.pay 接口返回的是一个 Form 表单)。

这类接口不能直接使用 exec() 方法的第二个形参 params 传递请求参数,而需要通过 exec() 方法的第三个形参 option.formData 传递,否则会报错

alipay-sdk 提供了一个 AlipayForm 的类,从 alipay-sdk/lib/form 引入,它实例化的对象是包含请求参数等信息的对象,通过调用实例的方法,向对象中添加请求参数,这个对象就用来传递给 exec()方法的 option.formData

实例可以通过 setMethod() 修改请求方式:

  • post(默认值):会返回一个 Form 表单的 HTML 代码片段
  • get:会返回一个支付宝收银台页面地址

官方指南:pageExecute()方法如何get请求

const AlipaySdk = require('alipay-sdk').default
const AlipayFormData = require('alipay-sdk/lib/form').default

// SDK 配置
const alipaySdkConfig = {
   
   ...}

// 创建 SDK 实例
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值