Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

alipay-sdk

Package Overview
Dependencies
Maintainers
6
Versions
71
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

alipay-sdk - npm Package Compare versions

Comparing version 2.0.2 to 3.0.0

.vscode/settings.json

446

lib/alipay.js

@@ -1,160 +0,302 @@

'use strict';
const crypto = require('crypto');
const urllib = require('urllib');
const extend = require('extend2');
const { formatParams, formatReqData, decamelize, camelcase, ALIPAY_ALGORITHM_MAPPING } = require('./util');
const defaultConfig = {
params: {
signType: 'RSA2',
charset: 'utf-8',
version: '1.0',
method: '',
},
getway: 'https://openapi.alipay.com/gateway.do',
// 私钥
privateKey: '',
// 支付宝公钥
alipayPublicKey: '',
appId: '',
timeout: 5000, // 5s
urllib,
// 返回 camelcase 数据
camelcase: false,
};
"use strict";
/**
* @author tudou527
* @email [tudou527@gmail.com]
*/
Object.defineProperty(exports, "__esModule", { value: true });
const fs = require("fs");
const is = require("is");
const crypto = require("crypto");
const urllib = require("urllib");
const request = require("request");
const camelcaseKeys = require("camelcase-keys");
const util_1 = require("./util");
const pkg = require('../package.json');
class AlipaySdk {
constructor(config) {
this.config = extend(true, {}, defaultConfig, camelcase(config));
}
/**
* 执行请求
* @param {string} method 调用接口方法名,比如 alipay.ebpp.bill.add
* @param {object} bizContext 业务请求参数
* @param {object} publicArgs 公共请求参数
* @param {Boolean} validateSign 是否验签
* @param {object} log 可选日志记录对象
* @return {Promise} 请求执行结果
*/
execute(method, bizContext, publicArgs, validateSign, log) {
const config = this.config;
const params = formatReqData(method, bizContext, publicArgs, config);
return new Promise((resolve, reject) => {
log && log.info('start execute method: %s , params: %s, config: %s,', method, JSON.stringify(params), JSON.stringify(config));
config.urllib.request(config.getway, {
data: decamelize(params),
dataType: 'json',
timeout: config.timeout,
method: 'GET',
})
.then(ret => {
log && log.info('execute method: %s , params: %s, got resonse: %s', method, JSON.stringify(params), JSON.stringify(ret));
if (ret.status === 200) {
// 示例响应格式
// {
// "alipay_trade_precreate_response": {
// "code": "10000",
// "msg": "Success",
// "out_trade_no": "6141161365682511",
// "qr_code": "https:\/\/qr.alipay.com\/bax03206ug0kulveltqc80a8"
// },
// "sign": "VrgnnGgRMNApB1QlNJimiOt5ocGn4a4pbXjdoqjHtnYMWPYGX9AS0ELt8YikVAl6LPfsD7hjSyGWGjwaAYJjzH1MH7B2/T3He0kLezuWHsikao2ktCjTrX0tmUfoMUBCxKGGuDHtmasQi4yAoDk+ux7og1J5tL49yWiiwgaJoBE="
// }
const data = ret.data[method.replace(/\./g, '_') + '_response'];
const sign = ret.data.sign;
// 默认不验签
let validateSuccess = true;
if (validateSign) {
validateSuccess = this.checkResponseSign(data, sign, params.signType);
}
if (validateSuccess) {
if (config.camelcase) {
return resolve(camelcase(data));
constructor(config) {
if (!config.appId) {
throw Error('config.appId is required');
}
if (!config.privateKey) {
throw Error('config.privateKey is required');
}
config.privateKey = this.formatKey(config.privateKey, 'RSA PRIVATE KEY');
if (config.alipayPublicKey) {
config.alipayPublicKey = this.formatKey(config.alipayPublicKey, 'PUBLIC KEY');
}
this.config = Object.assign({
urllib,
gateway: 'https://openapi.alipay.com/gateway.do',
timeout: 5000,
camelcase: true,
signType: 'RSA2',
charset: 'utf-8',
version: '1.0',
}, camelcaseKeys(config));
this.sdkVersion = `alipay-sdk-nodejs-${pkg.version}`;
}
// 格式化 key
formatKey(key, type) {
const item = key.split('\n').map(val => val.trim());
// 删除包含 `RSA PRIVATE KEY / PUBLIC KEY` 等字样的第一行
if (item[0].includes(type)) {
item.shift();
}
// 删除包含 `RSA PRIVATE KEY / PUBLIC KEY` 等字样的最后一行
if (item[item.length - 1].includes(type)) {
item.pop();
}
return `-----BEGIN ${type}-----\n${item.join('')}\n-----END ${type}-----`;
}
// 格式化请求 url(按规范把某些固定的参数放入 url)
formatUrl(url, params) {
let requestUrl = url;
// 需要放在 url 中的参数列表
const urlArgs = [
'app_id', 'method', 'format', 'charset',
'sign_type', 'sign', 'timestamp', 'version',
'notify_url', 'return_url', 'auth_token', 'app_auth_token',
];
for (const key in params) {
if (urlArgs.indexOf(key) > -1) {
const val = encodeURIComponent(params[key]);
requestUrl = `${requestUrl}${requestUrl.includes('?') ? '&' : '?'}${key}=${val}`;
// 删除 postData 中对应的数据
delete params[key];
}
return resolve(data);
}
}
reject(ret);
})
.catch(err => {
log && log.error('execute method: %s , params: %s, got error: %s', method, JSON.stringify(params), JSON.stringify(err));
reject(err);
});
});
}
/**
* 执行 page 类接口请求
* @param {string} method 调用接口方法名,比如 alipay.trade.page.pay
* @param {object} bizContext 业务请求参数
* @param {object} publicArgs 公共请求参数
* @param {object} log 可选日志记录对象
* @return {Promise} 可提交的表单
*/
page_execute(method, bizContext, publicArgs, log) {
const config = this.config;
const params = formatReqData(method, bizContext, publicArgs, config);
return new Promise(resolve => {
log && log.info('start page_execute method: %s , params: %s, config: %s,', method, JSON.stringify(params), JSON.stringify(config));
const formName = `alipaysubmit${Date.now()}`;
const postData = decamelize(params);
const inputs = [];
Object.keys(postData).forEach(key => {
const value = String(postData[key]).replace(/\"/g, '"');
inputs.push(`<input type="hidden" name="${key}" value="${value}" />`);
});
resolve(`<form action="${config.getway}" method="post" name="${formName}" id="${formName}">
${inputs.join('')}
</form>
<script>document.forms["${formName}"].submit();</script>`);
});
}
// response 参数验签
checkResponseSign(signArgs, signStr, signType) {
signType = signType || 'RSA2';
if (!this.config.alipayPublicKey || this.config.alipayPublicKey === '') {
// 支付宝公钥不存在时不做验签
return true;
return { execParams: params, url: requestUrl };
}
if (!signArgs) {
// 带验签的参数不存在时返回失败
return false;
// 文件上传
multipartExec(method, option = {}) {
const config = this.config;
const signParams = {};
const formData = {};
const infoLog = (option.log && is.fn(option.log.info)) ? option.log.info : null;
const errorLog = (option.log && is.fn(option.log.error)) ? option.log.error : null;
option.formData.getFields().forEach((field) => {
// 字段加入签名参数(文件不需要签名)
signParams[field.name] = field.value;
formData[field.name] = field.value;
});
option.formData.getFiles().forEach((file) => {
// 单独处理文件类型
formData[file.fieldName] = fs.createReadStream(file.path);
});
// 计算签名
const signData = util_1.sign(method, signParams, config);
// 格式化 url
const { url } = this.formatUrl(config.gateway, signData);
infoLog && infoLog('[AlipaySdk]start exec url: %s, method: %s, params: %s', url, method, JSON.stringify(signParams));
return new Promise((resolve, reject) => {
request.post({
url,
formData,
json: false,
timeout: config.timeout,
headers: { 'user-agent': this.sdkVersion },
}, (err, {}, body) => {
if (err) {
err.message = '[AlipaySdk]exec error';
errorLog && errorLog(err);
reject(err);
}
infoLog && infoLog('[AlipaySdk]exec response: %s', body);
const result = JSON.parse(body);
const responseKey = `${method.replace(/\./g, '_')}_response`;
const data = result[responseKey];
// 验签
const validateSuccess = option.validateSign ? this.checkResponseSign(body, responseKey) : true;
if (validateSuccess) {
resolve(config.camelcase ? camelcaseKeys(data) : data);
}
else {
reject({ serverResult: body, errorMessage: '[AlipaySdk]验签失败' });
}
reject({ serverResult: body, errorMessage: '[AlipaySdk]HTTP 请求错误' });
});
});
}
if (signArgs.sub_code) {
// 业务系统返回异常时不需要验签(返回成功)
return true;
// page 类接口
pageExec(method, option = {}) {
const signParams = { alipaySdk: this.sdkVersion };
const config = this.config;
const infoLog = (option.log && is.fn(option.log.info)) ? option.log.info : null;
option.formData.getFields().forEach((field) => {
signParams[field.name] = field.value;
});
// 计算签名
const signData = util_1.sign(method, signParams, config);
// 格式化 url
const { url, execParams } = this.formatUrl(config.gateway, signData);
infoLog && infoLog('[AlipaySdk]start exec url: %s, method: %s, params: %s', url, method, JSON.stringify(signParams));
if (option.formData.getMethod() === 'get') {
return new Promise((resolve) => {
const query = Object.keys(execParams).map((key) => {
return `${key}=${encodeURIComponent(execParams[key])}`;
});
resolve(`${url}&${query.join('&')}`);
});
}
return new Promise((resolve) => {
// 生成表单
const formName = `alipaySDKSubmit${Date.now()}`;
resolve(`
<form action="${url}" method="post" name="${formName}" id="${formName}">
${Object.keys(execParams).map((key) => {
const value = String(execParams[key]).replace(/\"/g, '&quot;');
return `<input type="hidden" name="${key}" value="${value}" />`;
}).join('')}
</form>
<script>document.forms["${formName}"].submit();</script>
`);
});
}
// 参数存在,并且是正常的结果(不包含 sub_code)时才验签
const verifier = crypto.createVerify(ALIPAY_ALGORITHM_MAPPING[signType]);
verifier.update(JSON.stringify(signArgs), 'utf-8');
return verifier.verify(this.config.alipayPublicKey, signStr, 'base64');
}
// 通知验签
checkNotifySign(postData) {
const signStr = postData.sign;
const signType = postData.sign_type || 'RSA2';
if (!this.config.alipayPublicKey || !signStr || !signType) {
return false;
/**
*
* @param originStr 开放平台返回的原始字符串
* @param responseKey xx_response 方法名 key
*/
getSignStr(originStr, responseKey) {
// 待签名的字符串
let validateStr = originStr.trim();
// 找到 xxx_response 开始的位置
const startIndex = originStr.indexOf(`${responseKey}"`);
// 找到最后一个 “"sign"” 字符串的位置(避免)
const lastIndex = originStr.lastIndexOf('"sign"');
/**
* 删除 xxx_response 及之前的字符串
* 假设原始字符串为
* {"xxx_response":{"code":"10000"},"sign":"jumSvxTKwn24G5sAIN"}
* 删除后变为
* :{"code":"10000"},"sign":"jumSvxTKwn24G5sAIN"}
*/
validateStr = validateStr.substr(startIndex + responseKey.length + 1);
/**
* 删除最后一个 "sign" 及之后的字符串
* 删除后变为
* :{"code":"10000"},
* {} 之间就是待验签的字符串
*/
validateStr = validateStr.substr(0, lastIndex);
// 删除第一个 { 之前的任何字符
validateStr = validateStr.replace(/^[^{]*{/g, '{');
// 删除最后一个 } 之后的任何字符
validateStr = validateStr.replace(/\}([^}]*)$/g, '}');
return validateStr;
}
const verifier = crypto.createVerify(ALIPAY_ALGORITHM_MAPPING[signType]);
const signArgs = Object.assign({}, postData);
// 除去sign、sign_type 皆是待验签的参数。
delete signArgs.sign;
delete signArgs.sign_type;
const signData = formatParams(signArgs).decode;
verifier.update(signData, 'utf-8');
return verifier.verify(this.config.alipayPublicKey, signStr, 'base64');
}
/**
* 执行请求
* @param {string} method 调用接口方法名,比如 alipay.ebpp.bill.add
* @param {object} params 请求参数
* @param {object} params.bizContent 业务请求参数
* @param {Boolean} option 选项
* @param {Boolean} option.validateSign 是否验签
* @param {object} args.log 可选日志记录对象
* @return {Promise} 请求执行结果
*/
exec(method, params = {}, option = {}) {
if (option.formData) {
if (option.formData.getFiles().length > 0) {
return this.multipartExec(method, option);
}
/**
* fromData 中不包含文件时,认为是 page 类接口(返回 form 表单)
* 比如 PC 端支付接口 alipay.trade.page.pay
*/
return this.pageExec(method, option);
}
const config = this.config;
// 计算签名
const signData = util_1.sign(method, params, config);
const { url, execParams } = this.formatUrl(config.gateway, signData);
const infoLog = (option.log && is.fn(option.log.info)) ? option.log.info : null;
const errorLog = (option.log && is.fn(option.log.error)) ? option.log.error : null;
infoLog && infoLog('[AlipaySdk]start exec, url: %s, method: %s, params: %s', url, method, JSON.stringify(execParams));
return new Promise((resolve, reject) => {
config.urllib.request(url, {
method: 'POST',
data: execParams,
// 按 text 返回(为了验签)
dataType: 'text',
timeout: config.timeout,
headers: { 'user-agent': this.sdkVersion },
})
.then((ret) => {
infoLog && infoLog('[AlipaySdk]exec response: %s', ret);
if (ret.status === 200) {
/**
* 示例响应格式
* {"alipay_trade_precreate_response":
* {"code": "10000","msg": "Success","out_trade_no": "111111","qr_code": "https:\/\/"},
* "sign": "abcde="
* }
*/
const result = JSON.parse(ret.data);
const responseKey = `${method.replace(/\./g, '_')}_response`;
const data = result[responseKey];
// 按字符串验签
const validateSuccess = option.validateSign ? this.checkResponseSign(ret.data, responseKey) : true;
if (validateSuccess) {
resolve(config.camelcase ? camelcaseKeys(data) : data);
}
else {
reject({ serverResult: ret, errorMessage: '[AlipaySdk]验签失败' });
}
}
reject({ serverResult: ret, errorMessage: '[AlipaySdk]HTTP 请求错误' });
})
.catch((err) => {
err.message = '[AlipaySdk]exec error';
errorLog && errorLog(err);
reject(err);
});
});
}
// 结果验签
checkResponseSign(signStr, responseKey) {
if (!this.config.alipayPublicKey || this.config.alipayPublicKey === '') {
console.warn('config.alipayPublicKey is empty');
// 支付宝公钥不存在时不做验签
return true;
}
// 带验签的参数不存在时返回失败
if (!signStr) {
return false;
}
// 根据服务端返回的结果截取需要验签的目标字符串
const validateStr = this.getSignStr(signStr, responseKey);
// 服务端返回的签名
const serverSign = JSON.parse(signStr).sign;
// 参数存在,并且是正常的结果(不包含 sub_code)时才验签
const verifier = crypto.createVerify(util_1.ALIPAY_ALGORITHM_MAPPING[this.config.signType]);
verifier.update(validateStr, 'utf8');
return verifier.verify(this.config.alipayPublicKey, serverSign, 'base64');
}
/**
* 通知验签
* @param postData {JSON} 服务端的消息内容
*/
checkNotifySign(postData) {
const signStr = postData.sign;
const signType = postData.sign_type || 'RSA2';
if (!this.config.alipayPublicKey || !signStr) {
return false;
}
const signArgs = Object.assign({}, postData);
// 除去sign、sign_type 皆是待验签的参数。
delete signArgs.sign;
delete signArgs.sign_type;
const decodeSign = Object.keys(signArgs).sort().filter(val => val).map((key) => {
let value = signArgs[key];
if (Array.prototype.toString.call(value) !== '[object String]') {
value = JSON.stringify(value);
}
return `${key}=${decodeURIComponent(value)}`;
}).join('&');
const verifier = crypto.createVerify(util_1.ALIPAY_ALGORITHM_MAPPING[signType]);
verifier.update(decodeSign, 'utf8');
return verifier.verify(this.config.alipayPublicKey, signStr, 'base64');
}
}
module.exports = AlipaySdk;
exports.default = AlipaySdk;

@@ -1,100 +0,52 @@

'use strict';
const moment = require('moment');
const decamelize = require('decamelize');
const camelcase = require('camelcase');
const isPlainObject = require('is-plain-object');
const crypto = require('crypto');
"use strict";
/**
* @author tudou527
* @email [tudou527@gmail.com]
*/
Object.defineProperty(exports, "__esModule", { value: true });
const crypto = require("crypto");
const moment = require("moment");
const iconv = require("iconv-lite");
const snakeCaseKeys = require("snakecase-keys");
const ALIPAY_ALGORITHM_MAPPING = {
RSA: 'RSA-SHA1',
RSA2: 'RSA-SHA256',
RSA: 'RSA-SHA1',
RSA2: 'RSA-SHA256',
};
function camelcaseFn(o) {
if (isPlainObject(o)) {
const copy = {};
for (const key of Object.keys(o)) {
const camelcaseKey = camelcase(key);
copy[camelcaseKey] = camelcaseFn(o[key]);
exports.ALIPAY_ALGORITHM_MAPPING = ALIPAY_ALGORITHM_MAPPING;
/**
* 签名
* @param {string} method 调用接口方法名,比如 alipay.ebpp.bill.add
* @param {object} bizContent 业务请求参数
* @param {object} publicArgs 公共请求参数
* @param {object} config sdk 配置
*/
function sign(method, params = {}, config) {
const bizContent = params.bizContent || null;
delete params.bizContent;
const signParams = Object.assign({
method,
appId: config.appId,
charset: config.charset,
version: config.version,
signType: config.signType,
timestamp: moment().format('YYYY-MM-DD HH:mm:ss'),
}, params);
if (bizContent) {
signParams.bizContent = JSON.stringify(snakeCaseKeys(bizContent));
}
return copy;
} else if (Array.isArray(o)) {
return o.map(item => camelcaseFn(item));
}
return o;
// params key 驼峰转下划线
const decamelizeParams = snakeCaseKeys(signParams);
// 排序
const signStr = Object.keys(decamelizeParams).sort().map((key) => {
let data = decamelizeParams[key];
if (Array.prototype.toString.call(data) !== '[object String]') {
data = JSON.stringify(data);
}
return `${key}=${iconv.encode(data, config.charset)}`;
}).join('&');
// 计算签名
const sign = crypto.createSign(ALIPAY_ALGORITHM_MAPPING[config.signType])
.update(signStr, 'utf8').sign(config.privateKey, 'base64');
return Object.assign(decamelizeParams, { sign });
}
function decamelizeFn(o) {
const copy = {};
for (const key of Object.keys(o)) {
const decamelizeKey = decamelize(key, '_');
copy[decamelizeKey] = o[key];
}
return copy;
}
function sign(params, privateKey) {
// 驼峰转下划线后对参数排序
const payload = getOrderedParamString(decamelizeFn(params));
return signOriginal(payload, privateKey, params.signType);
}
function signOriginal(params, privateKey, signType) {
const sig = crypto.createSign(ALIPAY_ALGORITHM_MAPPING[signType || 'RSA2']);
sig.update(params, 'utf-8');
return sig.sign(privateKey, 'base64');
}
function getOrderedParamString(params, needEncode) {
return Object.keys(params).sort().map(key => {
let data = params[key];
if (Array.prototype.toString.call(data) !== '[object String]') {
data = JSON.stringify(data);
}
const value = needEncode ? encodeURIComponent(data) : data;
return `${key}=${value}`;
})
.join('&');
}
module.exports = {
camelcase: camelcaseFn,
decamelize: decamelizeFn,
formatParams(params) {
const decode = [];
const encode = [];
Object.keys(params).sort().forEach(key => {
let value = params[key];
if (value === '' || value === undefined) {
return;
}
if (Array.prototype.toString.call(value) !== '[object String]') {
value = JSON.stringify(value);
}
decode.push(`${key}=${decodeURIComponent(value)}`);
encode.push(`${key}=${encodeURIComponent(value)}`);
});
return { decode: decode.join('&'), encode: encode.join('&') };
},
formatReqData(method, bizContext, publicArgs, config) {
publicArgs = publicArgs || {};
const params = Object.assign({}, config.params, {
appId: config.appId,
method,
timestamp: moment().format('YYYY-MM-DD HH:mm:ss'),
}, publicArgs);
if (bizContext) {
params.bizContent = JSON.stringify(decamelizeFn(bizContext));
}
const signature = sign(params, config.privateKey);
params.sign = signature;
return params;
},
ALIPAY_ALGORITHM_MAPPING,
};
exports.sign = sign;
{
"name": "alipay-sdk",
"version": "2.0.2",
"version": "3.0.0",
"description": "",
"main": "index.js",
"main": "lib/alipay.js",
"scripts": {
"pub": "npm version patch && git push origin && git push origin --tag && npm publish && tnpm sync",
"test": "mocha",
"ci": "istanbul cover _mocha"
"tsc": "./node_modules/.bin/tsc -p ./tsconfig.json",
"pub": "npm run tsc && npm version patch && git push origin && git push origin --tag && npm publish && tnpm sync",
"lint": "tslint -p ./tsconfig.json --fix",
"lint:no-fix": "tslint -p ./tsconfig.json",
"test": "npm run tsc && npm run lint && mocha",
"ci": "npm run tsc && npm run lint:no-fix && istanbul cover _mocha"
},
"author": "",
"author": "tudou527",
"license": "ISC",
"dependencies": {
"camelcase": "^4.0.0",
"decamelize": "^1.2.0",
"extend2": "^1.0.0",
"is-plain-object": "^2.0.1",
"@types/node": "^9.6.0",
"@types/urllib": "^2.25.0",
"camelcase-keys": "^4.2.0",
"is": "^3.2.1",
"moment": "^2.16.0",
"request": "^2.86.0",
"snakecase-keys": "^1.1.1",
"urllib": "^2.17.0"

@@ -25,5 +30,2 @@ },

"devDependencies": {
"@ali/ci": "^3.11.0",
"eslint": "^3.10.2",
"eslint-config-egg": "^3.2.0",
"istanbul": "^0.4.5",

@@ -33,4 +35,7 @@ "mocha": "^3.1.2",

"should": "^11.1.1",
"sinon": "^1.17.7"
"sinon": "^1.17.7",
"tslint": "^5.8.0",
"tslint-config-airbnb": "^5.4.2",
"typescript": "^2.6.2"
}
}

@@ -5,11 +5,257 @@ # Alipay SDK

## 使用步骤
> 第一次使用,请参考[支付宝开放平台配置](#支付宝开放平台配置)设置公钥
### 1. 注册支付宝开放平台(https://open.alipay.com/),并创建账号
# SDK 使用文档
### 2. 生成密钥
## 1. 实例化 SDK
```
// TypeScript
import AlipaySdk from 'alipay-sdk';
const alipaySdk = new AlipaySdk(AlipaySdkConfig);
```
`AlipaySdkConfig` 配置项
* 必选
* `appId`: `String` 开放平台上创建应用时生成的 appId
* `privateKey`: `String` 应用私钥
* `alipayPublicKey`: `String` 支付宝公钥
* 可选
* `timeout`: `Number` 网关超时时间,单位毫秒,默认 `5000`
* `camelcase`: `Boolean` 是否把服务端返回的数据中的字段名从下划线转为驼峰,默认 `true`
### 完整的例子:
```
// TypeScript
import AlipaySdk from 'alipay-sdk';
const alipaySdk = new AlipaySdk({
appId: '2016123456789012',
privateKey: fs.readFileSync('./private-key.pem', 'ascii'),
alipayPublicKey: fs.readFileSync('./public-key.pem', 'ascii'),
});
```
## 2. 通过 `exec` 调用 API
```
// TypeScript
try {
const result = await alipaySdk.exec(method, params, options);
// console.log(result);
} catch (err) {
// ...
}
```
* exec 参数列表
* 必选
* `method`: `String` 调用的 Api,比如 `koubei.marketing.campaign.tags.query`
* 可选
* `params`: `Object` Api 的请求参数(包含公共参数和请求参数),其中请求参数(对应支付宝开放平台文档中的“请求参数“)通过 `bizContent` 传递
* `bizContent`: `Object` 所有的请求参数
* `options`: `Object` 可选项
* `validateSign`: `Boolean` 是否对返回值验签(依赖实例化时配置的”支付宝公钥“),默认 `false`
* `formData`: `Object` 文件上传类接口的请求参数,,默认 `null`
* `log`: Log 对象,存在时会调用 `info`、`error` 方法写日志,默认 `null` 即不写日志
* exec 返回值类型: `Promise`
### 完整的例子
```
// TypeScript
try {
const result = await alipaySdk.exec('alipay.security.risk.content.analyze', {
// bizContent 的内容为 alipay.security.risk.content.analyze 的请求参数
bizContent: {
appName: 'appName',
appScene: 'appMainScene',
publishDate: moment().format('YYYY-MM-DD HH:mm:ss'),
accountId: 'account',
accountType: '0',
appMainScene: 'appMainScene',
appMainSceneId: '12345678',
appSceneDataId: 'appSceneDataId',
text: '好好学习。',
linkUrls: [],
pictureUrls: [
'http://xxxx.aliyuncs.com/UvfTktYfmcBCshhCdeycbPqlXNRcZvKR.jpg',
],
},
}, {
// 验签
validateSign: true,
// 打印执行日志
log: this.logger,
});
// result 为 API 介绍内容中 “响应参数” 对应的结果
console.log(result);
} catch (err) {
//...
}
```
## 其他
### 文件上传类接口调用
```
// 引入 AlipayFormData 并实例化
import AlipayFormData from 'alipay-sdk/lib/form';
const formData = new AlipayFormData();
```
AlipayFormData 提供了下面 2 个方法,用于增加字段文件:
* `addField(fieldName, fieldValue)` 增加字段,包含 2 个参数
* `fieldName`: `String` 字段名
* `fieldValue`: `String` 字段值
* `addFile(fieldName, fileName, filePath)` 增加文件,包含 3 个参数
* `fieldName`: `String` 字段名
* `fileName`: `String` 文件名
* `filePath`: `String` 文件绝对路径
#### 完整的例子
```
// TypeScript
import AlipayFormData from 'alipay-sdk/lib/form';
const formData = new AlipayFormData();
// 增加字段
formData.addField('imageType', 'jpg');
formData.addField('imageName', '图片.jpg');
// 增加上传的文件
formData.addFile('imageContent', '图片.jpg', path.join(__dirname, './test.jpg'));
try {
const result = alipaySdk.exec(
'alipay.offline.material.image.upload',
// 文件上传类接口 params 需要设置为 {}
{},
{
// 通过 formData 设置请求参数
formData: formData,
validateSign: true,
},
);
/**
* result 为 API 介绍内容中 “响应参数” 对应的结果
* 调用成功的情况下,返回值内容如下:
* {
* "code":"10000",
* "msg":"Success",
* "imageId":"4vjkXpGkRhKRH78ylDPJ4QAAACMAAQED",
* "imageUrl":"http://oalipay-dl-django.alicdn.com/rest/1.0/image?fileIds=4vjkXpGkRhKRH78ylDPJ4QAAACMAAQED&zoom=original"
* }
*/
console.log(result);
} catch (err) {
//...
}
```
### 页面类接口调用
页面类接口默认返回的数据为 html 代码片段,比如 PC 支付接口 `alipay.trade.page.pay` 返回的内容为 Form 表单。
同文件上传,此类接口也需要通过 `AlipayFormData.addField` 来增加参数。此外,AlipayFormData 还提供了 `setMethod` 方法,用于直接返回 url:
* `setMethod(method)` 设置请求方法
* `method`: `'post' | 'get'` 默认为 post
#### 完整的例子
##### 返回 form 表单
```
// TypeScript
import AlipayFormData from 'alipay-sdk/lib/form';
const formData = new AlipayFormData();
formData.addField('notifyUrl', 'http://www.com/notify');
formData.addField('bizContent', {
out_trade_no: 'out_trade_no',
product_code: 'FAST_INSTANT_TRADE_PAY',
totalAmount: '0.01',
subject: '商品',
body: '商品详情',
});
try {
const result = alipaySdk.exec(
'alipay.offline.material.image.upload', {}, {
formData: formData,
},
);
// result 为 form 表单
console.log(result);
} catch (err) {}
```
##### 返回支付链接
```
// TypeScript
import AlipayFormData from 'alipay-sdk/lib/form';
const formData = new AlipayFormData();
// 调用 setMethod 并传入 get,会返回可以跳转到支付页面的 url
formData.setMethod('get');
formData.addField('notifyUrl', 'http://www.com/notify');
formData.addField('bizContent', {
out_trade_no: 'out_trade_no',
product_code: 'FAST_INSTANT_TRADE_PAY',
totalAmount: '0.01',
subject: '支付测试',
body: '支付测试',
});
try {
const result = alipaySdk.exec(
'alipay.offline.material.image.upload', {}, {
formData: formData,
},
);
// result 为可以跳转到支付链接的 url
console.log(result);
} catch (err) {}
```
# 支付宝开放平台配置
## 1. 注册支付宝开放平台账号
支付宝开放平台: https://open.alipay.com/
## 2. 生成密钥
1. 下载 RSA密钥工具:https://docs.open.alipay.com/291/106097/
2. 切换到生成秘钥 tab,秘钥格式选择“PKCS1(非JAVA适用)” [Differences between “BEGIN RSA PRIVATE KEY” and “BEGIN PRIVATE KEY”](https://stackoverflow.com/questions/20065304/differences-between-begin-rsa-private-key-and-begin-private-key?utm_medium=organic&utm_source=google_rich_qa&utm_campaign=google_rich_qa)
2. 切换到生成秘钥 tab,秘钥格式选择“PKCS1(非JAVA适用)”
> 不需要手动修改秘钥格式,SDK 会自动处理
![img](https://gw.alipayobjects.com/zos/rmsportal/WYvBOnJBmBzBovsqYePF.png)

@@ -19,5 +265,3 @@

```
-----BEGIN RSA PRIVATE KEY-----
// 粘贴上一步生成的私钥到这里(不需要换行)
-----END RSA PRIVATE KEY-----
```

@@ -28,7 +272,5 @@

```
-----BEGIN RSA PRIVATE KEY-----
MIIEpQIBAAKCAQEAqATL9/w/B5Siq/C0mKO8CoUqxX9gv2Fxs2Xz8n0Ce2O3qk+zzQxxwpgG77TMQ5JRaFZ8f1hA2Ax8DQVp9NLi5hqX3cZUpt8snWvc2Jz3hNWv81GqTDZCsMQD/HqgLURZxyw1yVHA2sayFcm8Exn1gqd1bNMSdy/VxhtfwKRxBq/vTNtfKus2E15/bQKB+l/mvroYrR5qYOAInEQt0HoTDFKL2+kvq3TD24gT/VbsfpJoy8FU3lT33LkYAOhHridveugXLbd7eK9e4iC02KV1loQBbL7R+UKdvh+5RZQfRIbQfKhDaSwQqTY0l+2u0b7W80BV8M1iMwQ8errtyUuWKQIDAQABAoIBAEcB5/XA7B5XCbyiuKA9qm3Dw8S9xXR8SSIpN0TG4jKlfOyETJee58D2oQ/TF/SCtNbkni7vbFAiTpbuL85hBbV7ja0TcZkofmF1QVtmUxEXggnR/KfC0sKDxK+CX4lh9pM/MugHHfsXuBGPNWXZNbHm9bBtL8OhOrZDwV7X4FCTgKw8qPBX+hO+RuUQ8iDfZMgUWkrSPCAT68XdLU4K9RrPYMHSmE9HgQhkNbtbLpbHgXxL81H9mIwA4DL3FMoh0IwJ+Yx12m1xC6mVQay2e2DRWfOiGFJWgE2EM1+KY1SR2WgsjNM2/Q1QmSijHbTOx2/gW7xbsuazNQRoptoFVIECgYEA1cslOJmWXa3BVTaV/o47bSSYEjwfg/bV9gDkqA9+33oxLvWehaOYjwsLmY9uid95sWD0mQtJj4pXr63e5SBnTd3vB2p5fJ2Cnt9vnpq/nHvnB0xPHB/DhAMCMYm1bV6gKSzimG1DJVsygjWrbz1lEQ0GMJSBidC0mLx2Jl+jCvECgYEAyTBAPzMvKt1OUTbg1UwqoktKOBCWbaTVNst22/NtLIxi0zAl80NgdbNLhH+zesFGnTmFnP/79SshntvbPNAlUOkL1BPPAhHoIUR7ubFxDeDGFQ+DIUtHKBzYSvbekRO1AEPNkhFA3NiYnRrDOGYC+utuyafCppuBSSXpgMzXjrkCgYEAxaEiaS3hB/vk6gappUSJvpzDTqfxYiW9J8kvlgOs/pyP9p7qyRKvphtJv8wNHLpOXiAIO6lpeJ0j7axGjXvkwuBTY4GTiBR6eK6HGhBm7BrFN8PcpVzfeZrmXjC0W8PLPgTV+p2WImQpTqCaNxyD3r0xaZr+HA2nxEEC3votV6ECgYEAnyQLrfJO3RkxWgyOzCnzj2z+yFpWo2Q/Q5it7E4hjZt+kI8FdedV5cRtd+GLlw5LTRKzHf1e0A/OCFrgkLoUymuNb7Q7iuefNrF1LO2u/8tM5Fvg3fUt1Az9Ck88voVYJ116vo/nPsoV7i+9PF90/AY/HEQXNLLNEY9rpPZjjAECgYEAk9RSfc1w5TJbW8EqqSJ+tgyfJ8zP/D9pnZ0zmXeryVwne7YQmOar6KlLGNBKxbMSF6JV+Yo0lPKKdDmeH8Iqbo6l2grDGyeNLOlTug3fgdtFfgvBzJmQNXd8qpR8smzPqbcYwYHZG39l7lZ+lx/h1+qDiEcMRu/r8h3gv04lMxA=
-----END RSA PRIVATE KEY-----
```
### 3. 设置应用公钥
## 3. 设置应用公钥

@@ -41,7 +283,5 @@ 1. 复制 2.2 中生成的应用公钥

**注意:** 1.0.x 只支持 RSA(SHA1WithRSA) 方式的签名,请务必设置 RSA 秘钥
![img](https://gw.alipayobjects.com/zos/rmsportal/CyUzmlKmpCNPAPdNevTd.png)
### 4. 保存支付宝公钥
## 4. 保存支付宝公钥

@@ -57,5 +297,3 @@ > “支付宝公钥”用于开放平台返回值的进行验签

```
-----BEGIN PUBLIC KEY-----
// 粘贴上一步复制的“支付宝公钥”到这里(不需要换行)
-----END PUBLIC KEY-----
```

@@ -66,47 +304,4 @@

```
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqATL9/w/B5Siq/C0mKO8CoUqxX9gv2Fxs2Xz8n0Ce2O3qk+zzQxxwpgG77TMQ5JRaFZ8f1hA2Ax8DQVp9NLi5hqX3cZUpt8snWvc2Jz3hNWv81GqTDZCsMQD/HqgLURZxyw1yVHA2sayFcm8Exn1gqd1bNMSdy/VxhtfwKRxBq/vTNtfKus2E15/bQKB+l/mvroYrR5qYOAInEQt0HoTDFKL2+kvq3TD24gT/VbsfpJoy8FU3lT33LkYAOhHridveugXLbd7eK9e4iC02KV1loQBbL7R+UKdvh+5RZQfRIbQfKhDaSwQqTY0l+2u0b7W80BV8M1iMwQ8errtyUuWKQIDAQAB
-----END PUBLIC KEY-----
```
## 调用 SDK
Exp:
```
const AlipaySdk = require('alipay-sdk');
const sdk = new AlipaySdk({
appId: '2016101300678716',
privateKey: fs.readFileSync('./private-key.pem', 'ascii'),
alipayPublicKey: fs.readFileSync('./public-key.pem', 'ascii'),
});
sdk.execute(method, bizContent)
.then(ret => {
// console.log(ret);
})
.catch(() => {
// ...
});
```
* alipaySDKConfig 配置参数
* 必选参数
* `appId`: `String` 开放平台上创建应用时生成的 appId
* `privateKey`: `String` 应用私钥
* `alipayPublicKey`: `String` 支付宝公钥
* 可选参数
* `timeout`: `Number` 网关超时时间
* `camelcase`: `Boolean` 是否把服务端返回的数据下划线转驼峰
* execute 方法参数列表
* 必选参数
* `method`: `String` 调用的 Api,比如 `koubei.marketing.campaign.tags.query`
* `bizContext`: `Object` Api 的请求参数(文档中的“请求参数“)
> **注:** 某些 Api 可能没有请求参数
* 可选参数
* `publicArgs`: `String` Api 的公共请求参数(系统会自动处理公共请求参数,某些 Api 有自己特殊的公共请求参数时,请在这里设置)
* `validateSign`: `String` 是否对返回值验签(依赖3.2中配置的”支付宝公钥“)
* `log`: Log 对象,存在时会调用 `info` 方法写执行日志
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc