4.13.0 • Published 10 months ago

alipay-sdk v4.13.0

Weekly downloads
1,103
License
MIT
Repository
github
Last release
10 months ago

Alipay OpenAPI SDK

NPM version CI Test coverage npm download

简介

Alipay OpenAPI SDK for Node.js / 用于给 Node.js 服务器提供调用支付宝开放平台的能力。 包括向支付宝服务器发起 OpenAPI 请求、订单信息生成,以及配套的证书、加签和验签能力。

基于支付宝 API v3 接口规范实现。

同时支持 Commonjs 和 ESM 两种模块依赖方式引入,通过 TypeScript 实现,HTTP Client 使用 urllib

环境要求

  • 需要 Node.js >= 18.20.0

安装依赖

npm install alipay-sdk --save

平台配置

  • 先前往支付宝开发平台-开发者中心完成开发者接入的一些准备工作,包括创建应用、为应用添加功能包、设置应用的接口加签方式等。
    • 可以使用 支付宝开放平台秘钥工具 获取所需的公私钥,并在平台上上传公钥。
    • 本 SDK 默认采用 PKCS1 的格式解析密钥,与密钥工具的默认生成格式不一致。 请使用密钥工具【格式转换】功能转为 PKCS1,或在本 SDK 初始化时显式指定 keyType: 'PKCS8'
  • 在设置加签方式结束之后,记录必要信息用于初始化 SDK。
    • 公钥证书模式(推荐): appId应用私钥应用公钥证书文件支付宝公钥证书文件支付宝根证书文件
    • 公钥模式:appId应用私钥应用公钥支付宝公钥

初始化 SDK

  • 代码示例中的路径和文件名仅做示范,请根据项目实际读取文件所在的位置
  • 请保存好私钥文件,避免信息泄露

普通公钥模式

import { AlipaySdk } from 'alipay-sdk';

// 实例化客户端
const alipaySdk = new AlipaySdk({
  // 设置应用 ID
  appId: 'your-APPID',
  // 设置应用私钥
  privateKey: fs.readFileSync('/path/to/private-key.pem', 'ascii'),
  // 设置支付宝公钥
  alipayPublicKey: fs.readFileSync('/path/to/alipay-public-key.pem', 'ascii'),
  // 密钥类型,请与生成的密钥格式保持一致,参考平台配置一节
  // keyType: 'PKCS1',
  // 设置网关地址,默认是 https://openapi.alipay.com
  // endpoint: 'https://openapi.alipay.com',
});

证书模式

import { AlipaySdk } from 'alipay-sdk';

const alipaySdk = new AlipaySdk({
  appId: '2016123456789012',
  privateKey: fs.readFileSync('/path/to/private-key.pem', 'ascii'),
  // 传入支付宝根证书、支付宝公钥证书和应用公钥证书。
  alipayRootCertPath: '/path/to/alipayRootCert.crt',
  alipayPublicCertPath: '/path/to/alipayCertPublicKey_RSA2.crt',
  appCertPath: '/path/to/appCertPublicKey.crt',
});

验证配置

可以使用如下基础接口请求服务端,以验证配置正确。

// https://opendocs.alipay.com/open-v3/668cd27c_alipay.user.deloauth.detail.query?pathHash=3ab93168
const result = await alipaySdk.curl('POST', '/v3/alipay/user/deloauth/detail/query', {
  body: {
    date: '20230102',
    offset: 20,
    limit: 1,
  },
});

console.log(result);

只要接口调用返回 responseHttpStatus 200,即代表验证配置成功

{
  data: {},
  responseHttpStatus: 200,
  traceId: '06033316171731016275628924348'
}

其余情况,如代码报错,则说明未配置成功。

快速使用

curl 示例代码

用于向支付宝服务器发起请求,与具体接口相关的业务参数。 下面以 统一收单交易支付接口 为示例

const result = await alipaySdk.curl('POST', '/v3/alipay/trade/pay', {
  body: {
    notify_url: 'http://www.your-notify.com/notify', // 通知回调地址
    out_trade_no: '商家的交易码,需保持唯一性',
    total_amount: '0.1',
    subject: '测试订单',
    // 更多参数请查看文档 https://opendocs.alipay.com/open-v3/08c7f9f8_alipay.trade.pay?scene=32&pathHash=8bf49b74
  }
});

console.log(result);
// {
//  "trade_no":"2013112011001004330000121536",
//  "out_trade_no":"6823789339978248",
//  "buyer_logon_id":"159****5620",
//  "total_amount":"120.88",
//  ...

使用 AlipayFormData 表单上传文件

部分接口需要上传文件。 SDK 内部封装了一个 Form 对象,用以在发起 multipart/form-data 请求时使用。 以 支付宝文件上传接口 为例:

import { AlipayFormData } from 'alipay-sdk';

const form = new AlipayFormData();
form.addFile('file_content', '图片.jpg', path.join(__dirname, './test.jpg'));

const uploadResult = await alipaySdk.curl<{
  file_id: string;
}>('POST', '/v3/alipay/open/file/upload', {
  form,
  body: {
    biz_code: 'openpt_appstore',
  },
});

console.log(uploadResult);
// {
//   data: { file_id: 'A*7Cr9T6IAAC4AAAAAAAAAAAAAATcnAA' },
//   responseHttpStatus: 200,
//   traceId: '06033316171731110716358764348'
// }

上传文件流

import fs from 'node:fs';
import { AlipayFormData } from 'alipay-sdk';

const form = new AlipayFormData();
form.addFile('file_content', '图片.jpg', fs.createReadStream('/path/to/test-file'));

const uploadResult = await alipaySdk.curl<{
  file_id: string;
}>('POST', '/v3/alipay/open/file/upload', {
  form,
  body: {
    biz_code: 'openpt_appstore',
  },
});

console.log(uploadResult);
// {
//   data: { file_id: 'A*7Cr9T6IAAC4AAAAAAAAAAAAAATcnAA' },
//   responseHttpStatus: 200,
//   traceId: '06033316171731110716358764348'
// }

上传文件内容

import fs from 'node:fs';
import { AlipayFormData } from 'alipay-sdk';

const form = new AlipayFormData();
form.addFile('file_content', '图片.jpg', fs.readFileSync('/path/to/test-file'));

const uploadResult = await alipaySdk.curl<{
  file_id: string;
}>('POST', '/v3/alipay/open/file/upload', {
  form,
  body: {
    biz_code: 'openpt_appstore',
  },
});

console.log(uploadResult);
// {
//   data: { file_id: 'A*7Cr9T6IAAC4AAAAAAAAAAAAAATcnAA' },
//   responseHttpStatus: 200,
//   traceId: '06033316171731110716358764348'
// }

pageExecute 示例代码

pageExecute 方法主要是用于网站支付接口请求链接生成,传入前台访问输入密码完成支付, 如电脑网站支付 alipay.trade.page.pay 等接口。

表单示例:

const bizContent = {
  out_trade_no: "ALIPfdf1211sdfsd12gfddsgs3",
  product_code: "FAST_INSTANT_TRADE_PAY",
  subject: "abc",
  body: "234",
  total_amount: "0.01"
};

// 支付页面接口,返回 HTML 代码片段,内容为 Form 表单
const html = alipaySdk.pageExecute('alipay.trade.page.pay', 'POST', {
  bizContent,
  returnUrl: 'https://www.taobao.com'
});
<form action="https://openapi.alipay.com/gateway.do?method=alipay.trade.app.pay&app_id=2021002182632749&charset=utf-8&version=1.0&sign_type=RSA2&timestamp=2023-02-28%2011%3A48%3A28&app_auth_token=202302BBbcfad868001a4df3bbfa99e8a6913F10&sign=j9DjDGgxLt3jbOQZy7q7Qu8baKWTl4hZlxOHa%2B46hC1djmFx%2FIyBqzQntPMurzz3f8efXJsalZz3nqZ9ClowCCxBfBvqE0cdzCDAeQ1GMgjd7dbWgjfNNcqKgmJPsIkLaHnP5vTvj%2BA27SqkeZCMbeVfv%2B4nYurXaFB9dNBtA%3D%3D" method="post" name="alipaySDKSubmit1677556108819" id="alipaySDKSubmit1677556108819">
    <input type="hidden" name="alipay_sdk" value="alipay-sdk-nodejs-3.3.0" />
    <input type="hidden" name="biz_content" value="{&quot;out_trade_no&quot;:&quot;ziheng-test-eeee&quot;,&quot;product_code&quot;:&quot;QUICK_MSECURITY_PAY&quot;,&quot;subject&quot;:&quot;订单标题&quot;,&quot;total_amount&quot;:&quot;0.01&quot;,&quot;body&quot;:&quot;订单描述&quot;}" />
</form>
<script>document.forms["alipaySDKSubmit1677556108819"].submit();</script>

支付链接示例:

// 支付页面接口,返回支付链接,交由用户打开,会跳转至支付宝网站
const url = sdk.pageExecute('alipay.trade.page.pay', 'GET', {
  bizContent,
  returnUrl: 'https://www.taobao.com'
});

// 返回示例:https://openapi.alipay.com/gateway.do?method=alipay.trade.app.pay&app_id=2021002182632749&charset=utf-8&version=1.0&sign_type=RSA2&timestamp=2023-02-28%2011%3A46%3A35&app_auth_token=202302BBbcfaf3bbfa99e8a6913F10&sign=TPi33NcaKLRBLJDofon84D8itMoBkVAdJsfmIiQDScEw4NHAklXvcvn148A2t47YxDSK0urBnhS0%2BEV%2BVR6h6aKgp931%2FfFbG1I3SAguMjMbr23gnbS68d4spcQ%3D%3D&alipay_sdk=alipay-sdk-nodejs-3.3.0&biz_content=blabla

sdkExecute 示例代码

sdkExecute 方法主要是服务端生成请求字符串使用的,不会直接支付扣款,需传值到客户端进行调用收银台输入密码完成支付, 如 App 支付接口 alipay.trade.app.pay

// App 支付接口,生成请求字符串,
const orderStr = sdk.sdkExecute('alipay.trade.app.pay', {
  bizContent: {
    out_trade_no: "ALIPfdf1211sdfsd12gfddsgs3",
    product_code: "FAST_INSTANT_TRADE_PAY",
    subject: "abc",
    body: "234",
    total_amount: "0.01"
},
  returnUrl: 'https://www.taobao.com'
});

console.log(orderStr);
// method=alipay.trade.app.pay&app_id=2021002182632749&charset=utf-8&version=1.0&sign_type=RSA2&timestamp=2023-02-24%2016%3A20%3A28&app_auth_token=202302BBbcfad868001a4df3bbfa99e8a6913F10&sign=M%2B2sTNATtUk3i8cOhHGtqjVDHIHSpPReZgjfLfIgbQD4AvI%2Fh%2B%2FS2lkqfJVnI%2Bu0IQ2z7auE1AYQ0wd7yPC4%2B2m5WnN21Q6uQhCCHOsg30mXdnkdB3rgXIiFOSuURRwnaiBmKNKdhaXel51fxYZOTOApV47K6ZUsOlPxc%2FVJWUnC7Hrl64%2BAKqtbv%2BcaefzapYsJwGDzMAGccHGfxevSoZ2Ev7S0FsrDe4LBx4m%2BCWSIFASWFyWYxJq%2BJg7LH1HJqBdBk1jjh5JJ3bNlEqJk8MEFU7sNRae2ErdEPOwCchWkQOaVGOGpFlEHuTSvxnAKnjRkFerE14v%2BVm6weC1Tbw%3D%3D&alipay_sdk=alipay-sdk-nodejs-3.2.0&biz_content=%7B%22out_trade_no%22%3A%22ziheng-test-eeee%22%2C%22product_code%22%3A%22QUICK_MSECURITY_PAY%22%2C%22subject%22%3A%22%E8%AE%A2%E5%8D%95%E6%A0%87%E9%A2%98%22%2C%22total_amount%22%3A%220.01%22%2C%22body%22%3A%22%E8%AE%A2%E5%8D%95%E6%8F%8F%E8%BF%B0%22%7D

// 返回支付宝客户端之后,在【小程序中】通过 my.tradePay 进行调用。
// 详见:https://opendocs.alipay.com/mini/api/openapi-pay
my.tradePay({
  // 服务端生成的字符串,即上面返回的 orderStr
  orderStr,
  success: (res) => {
    my.alert({
      content: JSON.stringify(res),
    });
  },
  fail: (res) => {
    my.alert({
      content: JSON.stringify(res),
    });
  }
});

exec 示例代码(已废弃,请使用 curl 代替)

用于向支付宝服务器发起请求。与具体接口相关的业务参数,需要放在 bizContent 中。

const result = await alipay.exec('alipay.trade.pay', {
  notify_url: 'http://www.your-notify.com/notify', // 通知回调地址
  bizContent: {
    out_trade_no: '商家的交易码,需保持唯一性',
    total_amount: '0.1',
    subject: '测试订单',
  }
});

⚠️⚠️⚠️ 注意:部分接口的请求参数不在 bizContent 中, 如 alipay.system.oauth.token, 具体可参考官网各接口定义。

通知验签

部分接口会设置回调地址,用于支付宝服务器向业务服务器通知业务情况(如交易成功)等。 此时业务服务应该验证该回调的来源安全性,确保其确实由支付宝官方发起。 SDK 提供了对应的通知验签能力。

// 获取 queryObj,如 ctx.query, router.query
// 如服务器未将 queryString 转化为 object,需要手动转化
const queryObj = {
  sign_type: 'RSA2',
  sign: 'QfTb8tqE1BMhS5qAn.....',
  gmt_create: '2019-08-15 15:56:22',
  other_biz_field: '....',
}

// true | false
const success = sdk.checkNotifySign(queryObj);

如果遇到验签失败,请尝试使用 checkNotifySignV2() 方法代替,它默认不会对 value 进行 decode 如 https://github.com/alipay/alipay-sdk-nodejs-all/issues/45 提到的常见问题。

const postData = {
  sign_type: 'RSA2',
  sign: 'QfTb8tqE1BMhS5qAn.....',
  gmt_create: '2019-08-15 15:56:22',
  other_biz_field: '....',
};

// true | false
const success = sdk.checkNotifySignV2(postData);

对加密内容进行解密

例如需要对小程序拿到的加密手机号码进行解密

const plainText = alipaySdk.aesDecrypt(getPhoneNumberResponse);

对前端返回的报文进行验签

参考 https://opendocs.alipay.com/common/02mse3#AES%20%E8%A7%A3%E5%AF%86%E5%87%BD%E6%95%B0 的算法

前端返回的内容

{
 "response": "hvDOnibG0DPcOFPNubK3DEfLQGL4=",
 "sign": "OIwk7zfZMp5GX78Ow==",
 "sign_type": "RSA2",
 "encrypt_type": "AES",
 "charset": "UTF-8"
}

通过 alipay-sdk 验签

// 注意,加密内容必须前后加上双引号
const signContent = '"hvDOnibG0DPcOFPNubK3DEfLQGL4="';
const sign = 'OIwk7zfZMp5GX78Ow==';
const signType = 'RSA2';
const signCheckPass = alipaySdk.rsaCheck(signContent, sign, signType);

console.log(signCheckPass);

通过 HTTP 代理服务器调用

在需要固定 IP 白名单调用的场景下,可以通过配置 config.proxyAgent 来指定 HTTP 代理服务器调用。

import { AlipaySdk, ProxyAgent } from 'alipay-sdk';

// 实例化客户端
const alipaySdk = new AlipaySdk({
  // 其他配置不展示
  // ...
  proxyAgent: new ProxyAgent('http(s)://your-http-proxy-address'),
});

// 后续的所有 http 调用都会走此 HTTP 代理服务器
const result = await alipaySdk.curl('POST', '/v3/alipay/user/deloauth/detail/query', {
  body: {
    date: '20230102',
    offset: 20,
    limit: 1,
  },
});

console.log(result);

alipay-sdk v3 到 v4 的升级说明

从 v3 到 v4 有以下不兼容变更,请参考示例代码进行更新

  • Node.js 需要升级到 >= 18.20.0 及以上版本,可以到 Node.js 官方网站下载更新
  • Commonjs 通过 require('alipay-sdk') 引入细微变化

    v3 是会直接导出到 module.exports

    const AlipaySdk = require('alipay-sdk');

    v4 是导出到 exports.AlipaySdk

    const { AlipaySdk } = require('alipay-sdk');
  • exec() 方法如果传递 options.formData 不包含文件,会抛出 TypeError 异常 提示使用 pageExec() 方法代替

打印调试日志的方式

通过 NODE_DEBUG 环境变量打印 alipay-sdk 相关的调试日志

NODE_DEBUG=alipay-sdk* node your-script.js

问题反馈

如您在使用 Alipay SDK for Node.js 过程中遇到问题, 欢迎前往 支付宝开放社区 发帖与支付宝工作人员和其他开发者一起交流, 或联系 支付宝开放平台客服 协助解决。

API

new AlipaySdk(config)

ParamTypeDescription
configAlipaySdkConfig初始化 SDK 配置

AlipaySdkConfig

参数说明类型必填
appId应用IDstring
privateKey应用私钥字符串。RSA 签名验签工具string
signType签名种类,默认值是 "RSA2""RSA2" | "RSA"
alipayPublicKey支付宝公钥(需要对返回值做验签时候必填,不填则会忽略验签)string
gateway网关string
timeout网关超时时间(单位毫秒),默认值是 5000number
camelcase是否把网关返回的下划线 foo_bar 转换为驼峰写法 fooBar,默认值是 trueboolean
keyType指定 privateKey 类型, 默认值是 "PKCS1""PKCS1" | "PKCS8"
appCertPath应用公钥证书文件路径string
appCertContent应用公钥证书文件内容string | Buffer
appCertSn应用公钥证书snstring
alipayRootCertPath支付宝根证书文件路径string
alipayRootCertContent支付宝根证书文件内容string | Buffer
alipayRootCertSn支付宝根证书snstring
alipayPublicCertPath支付宝公钥证书文件路径string
alipayPublicCertContent支付宝公钥证书文件内容string | Buffer
alipayCertSn支付宝公钥证书snstring
encryptKeyAES 密钥,调用 AES加 解密相关接口时需要string
wsServiceUrl服务器地址string

alipaySdk.curl<T = any>(httpMethod, path, options?) ⇒ Promise<AlipayCommonResult<T>>

curl 方式调用支付宝 API v3 协议接口

Returns: Promise<AlipayCommonResult<T>> - 请求执行结果

ParamTypeDescriptionRequired
httpMethodstringHTTP 请求方式,支持 GET, POST, PUT, DELETE
pathstringHTTP 请求 URL
optionsAlipayCURLOptions可选参数
options.queryRecord<string, string \| number>指该参数需在请求 URL 传参
options.bodyRecord<string, any>指该参数需在请求 JSON 传参
options.formAlipayFormData \| AlipayFormStream表单方式提交数据
options.requestIdstring调用方的 requestId,不填会默认生成 uuid v4
options.needEncryptboolean自动 AES 加解密,默认值是 false
options.appAuthTokenstring应用授权令牌,代商家调用支付宝开放接口必填
options.requestTimeoutnumber请求超时时间,默认使用 config.timeout

AlipayCommonResult<T>

响应结果

参数说明类型必须
dataHTTP 接口响应返回的 JSON 数据T
responseHttpStatusHTTP 接口响应状态码number
traceIdHTTP 接口响应 trace idstring

alipaySdk.sdkExecute(method, bizParams, options?) ⇒ string

生成请求字符串,用于客户端进行调用

Returns: string - 请求字符串

ParamTypeDescription
methodstring方法名
bizParamsIRequestParams请求参数
bizParams.bizContentobject业务请求参数
optionsISdkExecuteOptions可选参数
options.bizContentAutoSnakeCasebooleanbizContent 做驼峰参数转为小写 + 下划线参数,如 outOrderNo => out_order_no,默认 true,如果不需要自动转换,请设置为 false

alipaySdk.pageExecute(method, httpMethod, bizParams) ⇒ string

生成网站接口请求链接 URL 或 POST 表单 HTML

Returns: string - 请求链接 URL 或 POST 表单 HTML

ParamTypeDescription
methodstring方法名
httpMethodstring后续进行请求的方法。如为 GET,即返回 http 链接;如为 POST,则生成表单 HTML
bizParamsIRequestParams请求参数
bizParams.bizContentobject业务请求参数

deprecated alipaySdk.exec(method, bizParams, options) ⇒ Promise<AlipaySdkCommonResult>

执行请求,调用支付宝 API v2 协议接口

注意:此方法是为了让 alipay-sdk@3 尽量平滑升级到 alipay-sdk@4 保留, 请尽快使用 alipaySdk.curl() 代替,走 API v3 协议。

Returns: Promise<AlipaySdkCommonResult> - 请求执行结果

ParamTypeDescription
methodstring调用接口方法名,比如 alipay.ebpp.bill.add
bizParamsIRequestParams请求参数
bizParams.bizContentobject业务请求参数
optionsIRequestOption选项
options.validateSignBoolean是否验签
options.logobject可选日志记录对象

AlipaySdkCommonResult

响应结果

参数说明类型必须
code响应码。10000 表示成功,其余详见 https://opendocs.alipay.com/common/02km9fstring
msg响应讯息。Success 表示成功。string
sub_code错误代号string
sub_msg错误辅助信息string

IRequestParams

请求参数

参数说明类型必须
bizContent业务请求参数object
needEncrypt自动 AES 加解密boolean

alipaySdk.checkNotifySignV2(postData)

通知验签,默认不会对 value 进行 decode

Returns: Boolean - 是否验签成功

ParamTypeDescription
postDataJSON服务端的消息内容

alipaySdk.checkNotifySign(postData, raw)

通知验签

Returns: Boolean - 是否验签成功

ParamTypeDescription
postDataJSON服务端的消息内容
rawBoolean是否使用 raw 内容而非 decode 内容验签

alipaySdk.aesDecrypt(encryptedText)

对加密内容进行 AES 解密

Returns: String - 解密后的明文字符串

ParamTypeDescription
encryptedTextString加密内容字符串

License

MIT

Contributors

Made with contrib.rocks.

4.12.0

10 months ago

4.13.0

10 months ago

4.11.0

12 months ago

4.9.0

1 year ago

4.10.0

1 year ago

4.8.0

1 year ago

4.4.0

1 year ago

4.6.0

1 year ago

4.5.0

1 year ago

4.7.0

1 year ago

4.5.1

1 year ago

4.3.0

1 year ago

3.6.2

1 year ago

4.0.0

1 year ago

4.2.0

1 year ago

4.0.0-beta.5

1 year ago

4.0.0-beta.4

1 year ago

4.0.0-beta.3

1 year ago

4.0.0-beta.2

1 year ago

4.1.0

1 year ago

4.0.0-beta.1

1 year ago

4.0.0-beta.0

1 year ago

3.6.1

2 years ago

3.6.0

2 years ago

3.5.0

2 years ago

3.3.2-beta.2

2 years ago

3.4.0

2 years ago

1.0.0-beta.2

2 years ago

1.0.0-beta.3

2 years ago

3.3.1-beta.1

2 years ago

3.3.1

2 years ago

1.0.0-beta.1

2 years ago

3.3.0

2 years ago

3.1.8

4 years ago

3.2.0

4 years ago

3.1.7

4 years ago

3.1.6

4 years ago

3.1.5

5 years ago

3.1.4

5 years ago

3.1.3

5 years ago

3.1.2

5 years ago

3.1.1

5 years ago

3.0.9

5 years ago

3.1.0

5 years ago

3.0.8

6 years ago

3.0.7

6 years ago

3.0.6

6 years ago

3.0.5

6 years ago

3.0.4

7 years ago

3.0.3

7 years ago

3.0.2

7 years ago

3.0.1

7 years ago

3.0.0

7 years ago

2.0.2

7 years ago

2.0.1

7 years ago

1.0.24-0

8 years ago

1.0.21

8 years ago

1.0.20

8 years ago

1.0.19

8 years ago

1.0.18

8 years ago

1.0.16

8 years ago

1.0.14

8 years ago

1.0.11

8 years ago

1.0.7

9 years ago

1.0.6

9 years ago

1.0.5

9 years ago

1.0.4

9 years ago

1.0.3

9 years ago

1.0.2

9 years ago

1.0.1

9 years ago

1.0.0

9 years ago