跳到主要内容

🔷 TypeScript

声明

本 SDK 由 AI 生成,仅供参考使用。建议在实际生产环境使用前进行充分测试。

概述

平台 Node.js Server SDK 提供了便捷的服务端接入方式,支持签名生成、请求加密、响应验签和解密等核心功能。

功能特性

  • 支持 SHA256withRSA 签名算法
  • 支持 AES 对称加密/解密
  • 基于 axios 的 HTTP 客户端
  • 自动处理签名和加密逻辑
  • 完整的响应验签和解密
  • TypeScript 类型支持
  • Promise/async-await 异步支持

环境要求

  • Node.js 14.0+
  • npm 或 yarn

安装

安装依赖

npm install axios

package.json 依赖

{
"dependencies": {
"axios": "^1.6.0"
},
"devDependencies": {
"@types/node": "^20.0.0",
"typescript": "^5.0.0"
}
}

快速开始

1. 创建配置

const { KudianClient } = require('./lib/kudian/KudianClient');

// 创建配置
const config = {
gatewayUrl: 'https://pay.kudianvip.com', // 正式环境
// gatewayUrl: 'https://pay.test.kudianvip.com', // 测试环境
mchId: 'your_mch_id',
appId: 'your_app_id',
appPrivateKey: 'your_app_private_key', // Base64格式
appSecretKey: 'your_secret_key', // AES加密密钥
apiPublicKey: 'your_api_public_key' // Base64格式
};

// 创建客户端
const client = new KudianClient(config);

2. 发起API请求

const { KudianClient } = require('./lib/kudian/KudianClient');

// 构造业务参数
const bizParams = {
param1: 'value1',
param2: 'value2'
};

// 发送请求
client.post('/api/path', bizParams)
.then(response => {
// 解析响应
const apiResponse = JSON.parse(response);

if (apiResponse.code === 0) {
console.log('业务数据:', apiResponse.data);
} else {
console.log('请求失败:', apiResponse.msg);
}
})
.catch(error => {
console.error('请求异常:', error.message);
});

3. 使用 async-await

const { KudianClient } = require('./lib/kudian/KudianClient');

async function main() {
const client = new KudianClient(config);

try {
// 构造业务参数
const bizParams = {
param1: 'value1',
param2: 'value2'
};

// 发送请求
const response = await client.post('/api/path', bizParams);

// 解析响应
const apiResponse = JSON.parse(response);

if (apiResponse.code === 0) {
console.log('业务数据:', apiResponse.data);
} else {
console.log('请求失败:', apiResponse.msg);
}
} catch (error) {
console.error('请求异常:', error.message);
}
}

main();

核心 API

KudianClient

主客户端类,提供所有API调用功能。

配置参数

参数类型必填说明
gatewayUrlstring网关地址,正式环境: https://pay.kudianvip.com,测试环境: https://pay.test.kudianvip.com
mchIdstring商户编号
appIdstring应用ID
appPrivateKeystring应用私钥(Base64编码格式),用于请求签名
appSecretKeystringAES加密密钥,用于请求/响应内容加密
apiPublicKeystringAPI平台公钥(Base64编码格式),用于响应验签
timeoutnumber请求超时时间(毫秒),默认30000

主要方法

post(apiPath: string, bizParams: object): Promise<string>

发送POST请求到指定API路径。

参数:

  • apiPath: API路径,如 /api/pay/create
  • bizParams: 业务参数对象

返回:

  • Promise<string>: 自动解密后的业务数据JSON字符串

示例:

const params = {
order_no: 'ORDER202401010001',
amount: 10000,
subject: '测试订单'
};

const result = await client.post('/api/pay/create', params);

verifyNotify(notifyParams: object): boolean

验证回调通知的签名。

参数:

  • notifyParams: 回调参数对象

返回:

  • boolean: true-验签成功,false-验签失败

示例:

// 在你的路由处理函数中
app.post('/notify', async (req, res) => {
const params = req.body;

// 验证签名
if (!client.verifyNotify(params)) {
return res.send('FAIL');
}

// 获取业务数据(已自动解密)
const bizData = client.decryptNotify(params.result);
console.log('回调数据:', bizData);

// 处理业务逻辑...

return res.send('SUCCESS');
});

完整代码实现

1. ClientConfig.ts - 配置类

/**
* SDK配置接口
*/
export interface ClientConfig {
/** 网关地址 */
gatewayUrl: string;
/** 商户编号 */
mchId: string;
/** 应用ID */
appId: string;
/** 应用私钥(Base64格式) */
appPrivateKey: string;
/** API平台公钥(Base64格式) */
apiPublicKey: string;
/** AES加密密钥 */
appSecretKey: string;
/** 请求超时时间(毫秒),默认30000 */
timeout?: number;
/** 是否启用日志,默认false */
enableLog?: boolean;
}

/**
* 客户端配置类
*/
export class ClientConfig {
constructor(public config: ClientConfig) {
this.config = {
timeout: 30000,
enableLog: false,
...config
};
}
}

2. CryptoUtil.ts - 加密工具类

import crypto from 'crypto';

/**
* 加密工具类
*/
export class CryptoUtil {
private static readonly AES_ALGORITHM = 'aes-256-ecb';

/**
* AES加密
*
* @param plainText 明文
* @param key 密钥
* @returns Base64编码的密文
*/
static aesEncrypt(plainText: string, key: string): string {
// 确保密钥是32字节(AES-256)
const keyBytes = Buffer.from(key, 'utf8');
const keyBytes32 = Buffer.alloc(32);
const length = Math.min(keyBytes.length, 32);
keyBytes.copy(keyBytes32, 0, 0, length);

const cipher = crypto.createCipheriv(this.AES_ALGORITHM, keyBytes32, null);
let encrypted = cipher.update(plainText, 'utf8', 'base64');
encrypted += cipher.final('base64');

return encrypted;
}

/**
* AES解密
*
* @param cipherText Base64编码的密文
* @param key 密钥
* @returns 明文
*/
static aesDecrypt(cipherText: string, key: string): string {
// 确保密钥是32字节(AES-256)
const keyBytes = Buffer.from(key, 'utf8');
const keyBytes32 = Buffer.alloc(32);
const length = Math.min(keyBytes.length, 32);
keyBytes.copy(keyBytes32, 0, 0, length);

const decipher = crypto.createDecipheriv(this.AES_ALGORITHM, keyBytes32, null);
let decrypted = decipher.update(cipherText, 'base64', 'utf8');
decrypted += decipher.final('utf8');

return decrypted;
}

/**
* SHA256withRSA签名
*
* @param message 待签名消息
* @param privateKeyBytes 私钥字节数组(Base64解码后的DER格式)
* @returns Base64编码的签名
*/
static signSHA256withRSA(message: string, privateKeyBytes: Buffer): string {
const sign = crypto.createSign('SHA256');
sign.update(message);
sign.end();

const signature = sign.sign(privateKeyBytes);
return signature.toString('base64');
}

/**
* SHA256withRSA验签
*
* @param message 待验签消息
* @param publicKeyBytes 公钥字节数组(Base64解码后的DER格式)
* @param sign Base64编码的签名
* @returns true-验签成功,false-验签失败
*/
static verifySHA256withRSA(message: string, publicKeyBytes: Buffer, sign: string): boolean {
const verify = crypto.createVerify('SHA256');
verify.update(message);
verify.end();

const signature = Buffer.from(sign, 'base64');

try {
return verify.verify(publicKeyBytes, signature);
} catch (error) {
return false;
}
}
}

3. SignUtil.ts - 签名工具类

/**
* 签名工具类
*/
export class SignUtil {
/**
* 生成签名字符串
* 将参数按ASCII码排序后拼接成 key1=value1&key2=value2 格式
*
* @param params 参数对象
* @returns 待签名字符串
*/
static makeSignString(params: Record<string, string>): string {
// 过滤sign字段和空值
const filteredKeys = Object.keys(params)
.filter(key => key !== 'sign' && params[key] !== '' && params[key] !== null && params[key] !== undefined)
.sort();

// 拼接字符串
return filteredKeys.map(key => `${key}=${params[key]}`).join('&');
}
}

4. HttpClient.ts - HTTP客户端类

import axios, {AxiosInstance} from 'axios';

/**
* HTTP请求配置
*/
export interface HttpClientConfig {
/** 请求超时时间(毫秒) */
timeout?: number;
/** 代理配置 */
proxy?: any;
}

/**
* HTTP客户端类
*/
export class HttpClient {
private axiosInstance: AxiosInstance;

constructor(config: HttpClientConfig = {}) {
this.axiosInstance = axios.create({
timeout: config.timeout || 30000,
proxy: config.proxy,
headers: {
'Content-Type': 'application/json'
}
});
}

/**
* 发送POST请求
*
* @param url 请求URL
* @param headers 请求头
* @param requestBody 请求体(JSON字符串)
* @returns 响应体(JSON字符串)
*/
async post(url: string, headers: Record<string, string>, requestBody: string): Promise<string> {
try {
const response = await this.axiosInstance.post(url, requestBody, {
headers
});

return response.data;
} catch (error: any) {
if (error.response) {
throw new Error(`HTTP请求失败: ${error.response.status}`);
} else if (error.request) {
throw new Error('网络错误,无法连接到服务器');
} else {
throw new Error(`请求配置错误: ${error.message}`);
}
}
}
}

5. KudianClient.ts - 主客户端类

import {ClientConfig} from './ClientConfig';
import {HttpClient} from './HttpClient';
import {CryptoUtil} from './CryptoUtil';
import {SignUtil} from './SignUtil';
import crypto from 'crypto';

/**
* 酷点支付SDK主客户端
*/
export class KudianClient {
private config: ClientConfig;
private httpClient: HttpClient;

constructor(config: ClientConfig | ClientConfig['config']) {
// 兼容两种传入方式
if (config instanceof ClientConfig) {
this.config = config;
} else {
this.config = new ClientConfig(config);
}

this.httpClient = new HttpClient({
timeout: this.config.config.timeout || 30000
});
}

/**
* 发送POST请求
*
* @param apiPath API路径
* @param bizParams 业务参数
* @returns 解密后的业务数据JSON字符串
*/
async post(apiPath: string, bizParams: Record<string, any>): Promise<string> {
// 1. 构造完整请求URL
const url = this.config.config.gatewayUrl + apiPath;

// 2. 将业务参数转换为JSON并加密
const bizJson = JSON.stringify(bizParams);
const encryptedContent = CryptoUtil.aesEncrypt(bizJson, this.config.config.appSecretKey);

// 3. 构造公共参数
const publicParams: Record<string, string> = {
mch_id: this.config.config.mchId,
app_id: this.config.config.appId,
timestamp: Date.now().toString(),
nonce_str: this.generateNonceStr(),
sign_type: 'SHA',
content: encryptedContent,
version: '2.0'
};

// 4. 生成签名
const signString = SignUtil.makeSignString(publicParams);
const privateKeyBytes = Buffer.from(this.config.config.appPrivateKey, 'base64');
const sign = CryptoUtil.signSHA256withRSA(signString, privateKeyBytes);
publicParams['sign'] = sign;

// 5. 发送请求
const requestBody = JSON.stringify(publicParams);

if (this.config.config.enableLog) {
console.log(`请求URL: ${url}`);
console.log(`请求参数: ${requestBody}`);
}

const headers: Record<string, string> = {
'Content-Type': 'application/json'
};

const responseBody = await this.httpClient.post(url, headers, requestBody);

if (this.config.config.enableLog) {
console.log(`响应结果: ${responseBody}`);
}

// 6. 解析响应并验签
const response = JSON.parse(responseBody);
const code = response.code;

if (code === 0) {
// 成功响应,验证签名
const responseSign = response['sign'] || '';
const verifyParams: Record<string, string> = {};

for (const key in response) {
// 排除sign字段
if (key !== 'sign' && response[key] !== null && response[key] !== undefined) {
verifyParams[key] = String(response[key]);
}
}

const verifyString = SignUtil.makeSignString(verifyParams);
const publicKeyBytes = Buffer.from(this.config.config.apiPublicKey, 'base64');
const verifyResult = CryptoUtil.verifySHA256withRSA(
verifyString,
publicKeyBytes,
responseSign
);

if (!verifyResult) {
throw new Error('响应签名验证失败');
}

// 解密业务数据
const encryptedResult = response['result'] || '';
const decryptedData = CryptoUtil.aesDecrypt(encryptedResult, this.config.config.appSecretKey);

if (this.config.config.enableLog) {
console.log(`解密后的业务数据: ${decryptedData}`);
}

return decryptedData;
} else {
// 失败响应
const msg = response['msg'] || '未知错误';
throw new Error(`请求失败: code=${code}, msg=${msg}`);
}
}

/**
* 验证回调通知签名
*
* @param notifyParams 回调参数
* @returns true-验签成功,false-验签失败
*/
verifyNotify(notifyParams: Record<string, string>): boolean {
const sign = notifyParams['sign'];
if (!sign) {
return false;
}

const verifyParams = {...notifyParams};
const verifyString = SignUtil.makeSignString(verifyParams);

const publicKeyBytes = Buffer.from(this.config.config.apiPublicKey, 'base64');
return CryptoUtil.verifySHA256withRSA(verifyString, publicKeyBytes, sign);
}

/**
* 解密回调通知的业务数据
*
* @param encryptedResult 加密的业务数据
* @returns 解密后的业务数据JSON字符串
*/
decryptNotify(encryptedResult: string): string {
return CryptoUtil.aesDecrypt(encryptedResult, this.config.config.appSecretKey);
}

/**
* 生成随机字符串
*
* @returns 随机字符串
*/
private generateNonceStr(): string {
return Buffer.from(crypto.randomBytes(16)).toString('hex').substring(0, 32);
}
}

6. index.ts - 导出入口

export {ClientConfig} from './ClientConfig';
export {KudianClient} from './KudianClient';
export {HttpClient} from './HttpClient';
export {CryptoUtil} from './CryptoUtil';
export {SignUtil} from './SignUtil';

可选实现

CustomHttpClient.ts - 自定义HTTP客户端

import {HttpClient} from './HttpClient';

/**
* 自定义HTTP客户端
* 可以基于fetch或其他HTTP库实现
*/
export class CustomHttpClient extends HttpClient {
async post(url: string, headers: Record<string, string>, requestBody: string): Promise<string> {
const response = await fetch(url, {
method: 'POST',
headers,
body: requestBody
});

if (!response.ok) {
throw new Error(`HTTP请求失败: ${response.status}`);
}

return await response.text();
}
}

/**
* 使用自定义客户端
*/
export class KudianClientWithCustom {
// 复用KudianClient的逻辑,但使用自定义HTTP客户端
constructor(config: ClientConfig, httpClient: HttpClient) {
// 实现逻辑...
}
}

ProxyHttpClient.ts - 代理支持

import {HttpClient} from './HttpClient';

/**
* 支持代理的HTTP客户端
*/
export class ProxyHttpClient extends HttpClient {
constructor(config: { timeout?: number; proxy?: string }) {
super({
timeout: config.timeout,
proxy: config.proxy ? {
host: config.proxy.split(':')[0],
port: parseInt(config.proxy.split(':')[1]),
protocol: 'http'
} : undefined
});
}
}

/**
* 使用示例
*/
const client = new KudianClient({
gatewayUrl: 'https://pay.kudianvip.com',
mchId: 'your_mch_id',
appId: 'your_app_id',
appPrivateKey: 'your_app_private_key',
appSecretKey: 'your_secret_key',
apiPublicKey: 'your_api_public_key',
timeout: 30000
}, new ProxyHttpClient({
timeout: 30000,
proxy: '127.0.0.1:8080'
}));

使用示例

完整示例:创建支付订单

const { KudianClient } = require('./lib/kudian/KudianClient');

// 1. 创建配置
const config = {
gatewayUrl: 'https://pay.test.kudianvip.com',
mchId: 'your_mch_id',
appId: 'your_app_id',
appPrivateKey: 'MIIEvQIBADANBgkqhkiG9w0BAQE...', // Base64格式的私钥
apiPublicKey: 'MIGfMA0GCSqGSIb3DQEBAQUAA...', // Base64格式的公钥
appSecretKey: 'your_secret_key_32_bytes', // 32字节的AES密钥
enableLog: true // 启用日志
};

// 2. 创建客户端
const client = new KudianClient(config);

// 3. 创建订单
async function createOrder() {
try {
// 构造业务参数
const bizParams = {
order_no: `ORDER${Date.now()}`,
amount: 10000,
currency: 'CNY',
subject: '测试商品',
notify_url: 'https://your-domain.com/notify'
};

// 发送请求
const result = await client.post('/api/pay/create', bizParams);

// 解析响应
const data = JSON.parse(result);

console.log('支付订单创建成功!');
console.log('订单号:', data.order_no);
console.log('支付URL:', data.pay_url);

} catch (error) {
console.error('订单创建失败:', error.message);
}
}

createOrder();

Express 回调通知处理示例

const express = require('express');
const { KudianClient } = require('./lib/kudian/KudianClient');

const app = express();
app.use(express.json());

// 创建客户端
const config = {
gatewayUrl: 'https://pay.kudianvip.com',
mchId: 'your_mch_id',
appId: 'your_app_id',
appPrivateKey: 'your_app_private_key',
appSecretKey: 'your_secret_key',
apiPublicKey: 'your_api_public_key'
};
const client = new KudianClient(config);

// 处理支付回调
app.post('/notify/pay', async (req, res) => {
try {
// 1. 验证签名
const params = req.body;
if (!client.verifyNotify(params)) {
console.error('签名验证失败');
return res.status(400).send('FAIL');
}

// 2. 解密业务数据
const bizData = client.decryptNotify(params.result);
console.log('收到支付回调:', bizData);

// 3. 解析业务数据并处理
const data = JSON.parse(bizData);
// TODO: 根据业务逻辑处理支付结果
// 更新订单状态、发货等

// 4. 返回成功
return res.send('SUCCESS');

} catch (error) {
console.error('处理回调失败:', error.message);
return res.status(500).send('FAIL');
}
});

app.listen(3000, () => {
console.log('Server is running on port 3000');
});

Koa 回调通知处理示例

const Koa = require('koa');
const Router = require('@koa/router');
const { KudianClient } = require('./lib/kudian/KudianClient');

const app = new Koa();
const router = new Router();

// 创建客户端
const config = {
gatewayUrl: 'https://pay.kudianvip.com',
mchId: 'your_mch_id',
appId: 'your_app_id',
appPrivateKey: 'your_app_private_key',
appSecretKey: 'your_secret_key',
apiPublicKey: 'your_api_public_key'
};
const client = new KudianClient(config);

// 处理支付回调
router.post('/notify/pay', async (ctx) => {
try {
// 1. 验证签名
const params = ctx.request.body;
if (!client.verifyNotify(params)) {
console.error('签名验证失败');
ctx.status = 400;
ctx.body = 'FAIL';
return;
}

// 2. 解密业务数据
const bizData = client.decryptNotify(params.result);
console.log('收到支付回调:', bizData);

// 3. 解析业务数据并处理
const data = JSON.parse(bizData);
// TODO: 根据业务逻辑处理支付结果
// 更新订单状态、发货等

// 4. 返回成功
ctx.body = 'SUCCESS';

} catch (error) {
console.error('处理回调失败:', error.message);
ctx.status = 500;
ctx.body = 'FAIL';
}
});

app.use(router.routes());
app.listen(3000, () => {
console.log('Server is running on port 3000');
});

NestJS 回调通知处理示例

import {Controller, Post, Body} from '@nestjs/common';
import {KudianClient} from '../lib/kudian/KudianClient';

@Controller('notify')
export class PayNotifyController {
private client: KudianClient;

constructor() {
this.client = new KudianClient({
gatewayUrl: 'https://pay.kudianvip.com',
mchId: 'your_mch_id',
appId: 'your_app_id',
appPrivateKey: 'your_app_private_key',
appSecretKey: 'your_secret_key',
apiPublicKey: 'your_api_public_key'
});
}

@Post('pay')
async handlePayNotify(@Body() params: Record<string, string>): Promise<string> {
try {
// 1. 验证签名
if (!this.client.verifyNotify(params)) {
console.error('签名验证失败');
return 'FAIL';
}

// 2. 解密业务数据
const bizData = this.client.decryptNotify(params.result);
console.log('收到支付回调:', bizData);

// 3. 解析业务数据并处理
const data = JSON.parse(bizData);
// TODO: 根据业务逻辑处理支付结果
// 更新订单状态、发货等

// 4. 返回成功
return 'SUCCESS';

} catch (error) {
console.error('处理回调失败:', error.message);
return 'FAIL';
}
}
}

TypeScript 完整示例

import {KudianClient, ClientConfig} from './lib/kudian/KudianClient';

interface OrderData {
order_no: string;
amount: number;
currency: string;
subject: string;
notify_url: string;
}

interface PayResponse {
order_no: string;
pay_url: string;
}

async function main() {
// 1. 创建配置
const config: ClientConfig = {
gatewayUrl: 'https://pay.test.kudianvip.com',
mchId: 'your_mch_id',
appId: 'your_app_id',
appPrivateKey: 'MIIEvQIBADANBgkqhkiG9w0BAQE...',
apiPublicKey: 'MIGfMA0GCSqGSIb3DQEBAQUAA...',
appSecretKey: 'your_secret_key_32_bytes',
timeout: 30000,
enableLog: true
};

// 2. 创建客户端
const client = new KudianClient(config);

try {
// 3. 构造业务参数
const bizParams: OrderData = {
order_no: `ORDER${Date.now()}`,
amount: 10000,
currency: 'CNY',
subject: '测试商品',
notify_url: 'https://your-domain.com/notify'
};

// 4. 发送请求
const result = await client.post('/api/pay/create', bizParams);

// 5. 解析响应
const data: PayResponse = JSON.parse(result);

console.log('支付订单创建成功!');
console.log('订单号:', data.order_no);
console.log('支付URL:', data.pay_url);

} catch (error: any) {
console.error('订单创建失败:', error.message);
}
}

main();

批量请求示例

const { KudianClient } = require('./lib/kudian/KudianClient');

async function batchRequest() {
const client = new KudianClient(config);

const orders = [
{ order_no: 'ORDER001', amount: 10000 },
{ order_no: 'ORDER002', amount: 20000 },
{ order_no: 'ORDER003', amount: 30000 }
];

// 方式1: 串行请求
const results1 = [];
for (const order of orders) {
const result = await client.post('/api/pay/create', order);
results1.push(JSON.parse(result));
}

// 方式2: 并行请求
const requests = orders.map(order => client.post('/api/pay/create', order));
const results2 = await Promise.all(requests).then(responses =>
responses.map(r => JSON.parse(r))
);

console.log('批量请求完成');
}

异常处理

SDK可能抛出的异常:

异常类型说明处理建议
Error配置参数错误检查配置参数是否完整和正确
Error签名验签失败检查密钥是否正确
Error加解密失败检查appSecretKey是否正确
ErrorHTTP请求失败检查网络连接和网关地址

异常处理最佳实践

const { KudianClient } = require('./lib/kudian/KudianClient');

// 方式1: try-catch
try {
const result = await client.post('/api/path', params);
console.log('请求成功:', result);
} catch (error) {
console.error('请求失败:', error.message);
}

// 方式2: Promise.catch
client.post('/api/path', params)
.then(result => {
console.log('请求成功:', result);
})
.catch(error => {
console.error('请求失败:', error.message);
});

// 方式3: 使用错误包装
async function safeRequest(apiPath, params) {
try {
const result = await client.post(apiPath, params);
return { success: true, data: result };
} catch (error) {
return {
success: false,
error: error.message,
code: error.code || 'UNKNOWN_ERROR'
};
}
}

// 使用
const response = await safeRequest('/api/pay/create', orderParams);
if (response.success) {
console.log('订单创建成功');
} else {
console.error('订单创建失败:', response.error);
}

常见问题

1. 如何获取密钥?

  • app_private_key: 商户自行生成RSA密钥对,将公钥上传到商户后台
  • api_public_key: 从商户后台获取平台公钥
  • secret_key: 从商户后台获取或设置

2. 如何生成RSA密钥对?

可以使用OpenSSL命令生成:

# 生成私钥
openssl genrsa -out app_private_key.pem 2048

# 提取公钥
openssl rsa -in app_private_key.pem -pubout -out app_public_key.pem

# 转换为PKCS8格式
openssl pkcs8 -topk8 -inform PEM -in app_private_key.pem -outform PEM -nocrypt -out app_private_key_pkcs8.pem

# 转换为DER格式(Node.js需要)
openssl pkcs8 -topk8 -inform PEM -in app_private_key_pkcs8.pem -outform DER -nocrypt -out app_private_key.der
openssl rsa -in app_public_key.pem -pubout -outform DER -out app_public_key.der

# 转换为Base64格式
base64 -w 0 app_private_key.der
base64 -w 0 app_public_key.der

3. 如何使用自定义HTTP客户端?

const { KudianClient, HttpClient } = require('./lib/kudian/KudianClient');

// 继承HttpClient类
class MyCustomHttpClient extends HttpClient {
async post(url, headers, requestBody) {
// 自定义实现,例如添加重试逻辑
let retries = 3;
while (retries > 0) {
try {
return await super.post(url, headers, requestBody);
} catch (error) {
retries--;
if (retries === 0) throw error;
await new Promise(resolve => setTimeout(resolve, 1000));
}
}
}
}

// 使用自定义客户端
const client = new KudianClient(config, new MyCustomHttpClient());

4. 日志配置

SDK内置了日志功能,可以通过配置启用:

const { KudianClient } = require('./lib/kudian/KudianClient');

const config = {
gatewayUrl: 'https://pay.kudianvip.com',
mchId: 'your_mch_id',
appId: 'your_app_id',
appPrivateKey: 'your_app_private_key',
appSecretKey: 'your_secret_key',
apiPublicKey: 'your_api_public_key',
enableLog: true // 启用日志
};

// 自定义日志输出
const originalPost = KudianClient.prototype.post;
KudianClient.prototype.post = async function (apiPath, bizParams) {
console.log(`[KudianSDK] 开始请求: ${apiPath}`);
const startTime = Date.now();

try {
const result = await originalPost.call(this, apiPath, bizParams);
console.log(`[KudianSDK] 请求完成,耗时: ${Date.now() - startTime}ms`);
return result;
} catch (error) {
console.error(`[KudianSDK] 请求失败,耗时: ${Date.now() - startTime}ms`, error);
throw error;
}
};

5. 项目结构建议

注意: SDK 代码应集成到您的项目中,建议使用以下目录结构:

your-project/
├── lib/
│ └── kudian/
│ ├── ClientConfig.ts # 配置类
│ ├── CryptoUtil.ts # 加密工具类
│ ├── SignUtil.ts # 签名工具类
│ ├── HttpClient.ts # HTTP客户端类
│ ├── KudianClient.ts # 主客户端类
│ └── index.ts # 导出入口
├── examples/ # 使用示例
│ ├── express.js # Express示例
│ ├── koa.ts # Koa示例
│ └── nestjs.ts # NestJS示例
├── tests/ # 测试代码
│ └── client.test.ts # 单元测试
├── package.json
├── tsconfig.json
└── README.md

使用方式:

// 在您的业务代码中导入 SDK
import {KudianClient} from './lib/kudian/KudianClient';

// 创建客户端并使用
const client = new KudianClient(config);

6. TypeScript 配置示例

{
"compilerOptions": {
"target": "ES2020",
"module": "commonjs",
"lib": [
"ES2020"
],
"declaration": true,
"outDir": "./lib",
"rootDir": "./src",
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"moduleResolution": "node"
},
"include": [
"lib/**/*"
],
"exclude": [
"node_modules",
"tests"
]
}
预约咨询