├── .gitignore ├── .npmignore ├── README.md ├── index.js ├── package.json └── test ├── alipay.test.js ├── app.js └── index.html /.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | # Created by .ignore support plugin (hsz.mobi) 3 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | .idea 3 | /test -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [](https://www.npmjs.com/package/direct-alipay) 2 | [](https://www.npmjs.com/package/direct-alipay) 3 | [](https://npmjs.org/package/direct-alipay) 4 | 5 | # 支付宝 即时到账 NodeJS包 [demo](http://ccnu-aa.leanapp.cn/) 6 | 7 | ## 集成到你的项目 8 | 9 | #### 1.安装 10 | ```bash 11 | npm install direct-alipay 12 | ``` 13 | 14 | #### 2.配置支付宝参数 15 | ```js 16 | var directAlipay = require('direct-alipay'); 17 | directAlipay.config({ 18 | seller_email: 'jyjjh@mail.ccnu.edu.cn', 19 | partner: '2088911275465084', 20 | key: 'tws3ri4d3sg8ohc4t7k9dnj8kumvia05', 21 | return_url: 'http://127.0.0.1:3000/return' 22 | }); 23 | ``` 24 | 25 | 参数说明见[支付宝官方文档](https://openhome.alipay.com/platform/document.htm#webApp-directPay-API-direct) 26 | 27 | #### 3.传入订单参数,生成支付跳转URL 28 | ```js 29 | var url = directAlipay.buildDirectPayURL({ 30 | out_trade_no: Date.now().toString() + Math.random(),//业务侧需要为每个订单生成一个唯一订单号 31 | subject: '给华中师范大学贫困学生的捐赠',//订单标题 32 | body: 'body', 33 | total_fee: '1'//订单金额,单位元 34 | }); 35 | ``` 36 | 37 | #### 4.引导用户跳转到获得的URL,跳转到支付宝支付界面 38 | ```js 39 | window.location.href = url; 40 | ``` 41 | 42 | #### 5.用户支付完毕后,会跳转到第2步配置的return_url,在这里来判断订单是否成功支付 43 | ```js 44 | app.get('/return', function (req, res) { 45 | var params = req.query; 46 | directAlipay.verify(params).then(function() { 47 | //该通知是来自支付宝的合法通知 48 | }).catch(function(err) { 49 | console.error(err); 50 | }); 51 | }); 52 | ``` 53 | 54 | 支付宝回调通知见[官方文档](https://openhome.alipay.com/platform/document.htm#webApp-transPay-transpay-notify) 55 | 56 | ## 运行Demo 57 | 仔细`npm start`后,用浏览器打开`http://localhost:3000` 58 | 59 | ## 文档 60 | 61 | ##### `directAlipay` 62 | 所有方法的入口 63 | ```js 64 | var directAlipay = require('direct-alipay'); 65 | ``` 66 | 67 | ##### `directAlipay.config(params)` 68 | 配置支付宝基础配置,在使用前先配置. 69 | ```js 70 | directAlipay.config({ 71 | //签约支付宝账号或卖家收款支付宝帐户 72 | seller_email: 'jyjjh@mail.ccnu.edu.cn', 73 | //合作身份者ID,以2088开头由16位纯数字组成的字符串 74 | partner: '2088911275465084', 75 | //交易安全检验码,由数字和字母组成的32位字符串 76 | key: 'tws3ri4d3sg8ohc4t7k9dnj8kumvia05', 77 | //支付宝服务器通知的页面 78 | notify_url: 'http://127.0.0.1:3000/notify', 79 | //支付后跳转后的页面 80 | return_url: 'http://127.0.0.1:3000/' 81 | }); 82 | ``` 83 | 84 | 其它配置参数见[官方文档](https://openhome.alipay.com/platform/document.htm#webApp-directPay-API-direct) 85 | 86 | ##### `directAlipay.buildDirectPayURL(params)` 87 | 使用订单参数构造一个支付请求 88 | ```js 89 | directAlipay.buildDirectPayURL({ 90 | out_trade_no: '你的网站订单系统中的唯一订单号匹配', 91 | subject: '订单名称显示在支付宝收银台里的“商品名称”里,显示在支付宝的交易管理的“商品名称”的列表里', 92 | body: '订单描述、订单详细、订单备注,显示在支付宝收银台里的“商品描述”里', 93 | total_fee: '订单总金额' 94 | }); 95 | ``` 96 | 97 | 返回支付宝支付请求URL 浏览器跳转到该url支付 98 | 99 | ##### `directAlipay.verify(params)` 100 | 验证来自支付宝的通知是否合法 101 | ```js 102 | app.get('/notify', function (req, res) { 103 | var params = req.body; 104 | directAlipay.verify(params).then(function() { 105 | //该通知是来自支付宝的合法通知 106 | }).catch(function(err) { 107 | console.error(err); 108 | }) 109 | }); 110 | ``` 111 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var https = require('https'); 3 | var crypto = require('crypto'); 4 | var querystring = require('querystring'); 5 | 6 | var basicConfig = { 7 | alipay_gateway: 'https://mapi.alipay.com/gateway.do?', 8 | //字符编码格式 9 | _input_charset: 'UTF-8', 10 | //签名方式 不需修改 11 | sign_type: 'MD5' 12 | }; 13 | 14 | /** 15 | * https GET 对应的url 16 | * @param url @param url 要请求的url 17 | * @returns {Promise} 18 | */ 19 | function httpsGET(url) { 20 | return new Promise(function (resolve, reject) { 21 | var req = https.get(url, function (res) { 22 | res.on('data', function (data) { 23 | resolve(data); 24 | }); 25 | }); 26 | req.on('error', function (err) { 27 | reject(err); 28 | }); 29 | req.end(); 30 | }); 31 | } 32 | 33 | /** 34 | * 计算签名 35 | * @param json 36 | * @returns {string} 37 | */ 38 | function buildSign(json) { 39 | var keys = Object.keys(json); 40 | keys = keys.sort(); 41 | var map = {}; 42 | for (var i = 0; i < keys.length; i++) { 43 | var key = keys[i]; 44 | if (key !== 'sign' && key !== 'sign_type' && json[key]) { 45 | map[key] = json[key]; 46 | } 47 | } 48 | var str = querystring.unescape(querystring.stringify(map)) + basicConfig.key; 49 | return crypto.createHash(basicConfig.sign_type).update(str, basicConfig._input_charset).digest('hex'); 50 | } 51 | 52 | /** 53 | * 配置 54 | * @param params 55 | * { 56 | * seller_email:签约支付宝账号或卖家收款支付宝帐户 57 | * partner:合作身份者ID,以2088开头由16位纯数字组成的字符串 58 | * key:交易安全检验码,由数字和字母组成的32位字符串 59 | * notify_url:支付宝服务器通知的页面 60 | * return_url:支付后跳转后的页面 61 | * } 62 | */ 63 | exports.config = function (params) { 64 | Object.assign(basicConfig, params); 65 | }; 66 | 67 | /** 68 | * 使用订单参数构造一个支付请求 69 | * @param orderParams 订单参数 70 | * { 71 | * body:订单描述、订单详细、订单备注,显示在支付宝收银台里的“商品描述”里 72 | * out_trade_no:你的网站订单系统中的唯一订单号匹配 73 | * subject:订单名称显示在支付宝收银台里的“商品名称”里,显示在支付宝的交易管理的“商品名称”的列表里。 74 | * total_fee:订单总金额,显示在支付宝收银台里的“应付总额”里 75 | * } 76 | * @returns {string} 支付宝支付请求URL 浏览器跳转到该url支付 77 | */ 78 | exports.buildDirectPayURL = function (orderParams) { 79 | var json = { 80 | service: 'create_direct_pay_by_user', 81 | payment_type: '1', 82 | _input_charset: basicConfig._input_charset, 83 | notify_url: basicConfig.notify_url, 84 | partner: basicConfig.partner, 85 | return_url: basicConfig.return_url, 86 | seller_email: basicConfig.seller_email 87 | }; 88 | Object.assign(json, orderParams); 89 | //加入签名结果与签名方式 90 | json.sign = buildSign(json); 91 | json.sign_type = basicConfig.sign_type; 92 | return basicConfig.alipay_gateway + querystring.stringify(json); 93 | }; 94 | 95 | /** 96 | * 验证来自支付宝的通知是否合法 97 | * @param params 来自支付宝的通知参数 98 | * @returns {Promise} 验证通过时resolve,失败时reject 99 | */ 100 | exports.verify = function (params) { 101 | return new Promise(function (resolve, reject) { 102 | var paramsSign = params.sign; 103 | var realSign = buildSign(params); 104 | if (paramsSign === realSign) { 105 | var url = basicConfig.alipay_gateway + 106 | querystring.stringify({ 107 | service: 'notify_verify', 108 | partner: basicConfig.partner, 109 | notify_id: params['notify_id'] 110 | }); 111 | httpsGET(url).then(function (data) { 112 | if (data.toString() === 'true') { 113 | resolve(true); 114 | } else { 115 | reject('来自alipay接口的结果为:验证结果不合法'); 116 | } 117 | }).catch(function (err) { 118 | reject('请求alipay接口发生网络错误:' + JSON.stringify(err)) 119 | }); 120 | } else { 121 | reject('sign验证不相等: ' + paramsSign + ' !== ' + realSign); 122 | } 123 | }); 124 | }; 125 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "direct-alipay", 3 | "version": "3.0.0", 4 | "description": "alipay direct pay nodejs api client", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "node ./test/app.js", 8 | "test": "mocha --recursive test/*.test.js" 9 | }, 10 | "keywords": [ 11 | "alipay", 12 | "api", 13 | "支付宝 即时到账" 14 | ], 15 | "author": "WuHaolin", 16 | "bugs": { 17 | "url": "https://github.com/gwuhaolin/direct-alipay/issues" 18 | }, 19 | "homepage": "https://github.com/gwuhaolin/direct-alipay", 20 | "repository": { 21 | "type": "git", 22 | "url": "git@github.com:gwuhaolin/direct-alipay.git" 23 | }, 24 | "license": "ISC", 25 | "devDependencies": { 26 | "body-parser": "^1.17.1", 27 | "express": "4.15.2" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /test/alipay.test.js: -------------------------------------------------------------------------------- 1 | var assert = require('assert'); 2 | var querystring = require('querystring'); 3 | var alipay = require('../index'); 4 | 5 | describe('index.js', function () { 6 | 7 | before(function () { 8 | alipay.config({ 9 | seller_email: 'jyjjh@mail.ccnu.edu.cn', 10 | partner: '2088911275465084', 11 | key: 'tws3ri4d3sg8ohc4t7k9dnj8kumvia05', 12 | notify_url: 'http://127.0.0.1:3000/notify' 13 | }) 14 | }); 15 | 16 | it('#buildDirectPayURL', function () { 17 | var url = alipay.buildDirectPayURL({ 18 | out_trade_no: 'out_trade_no', 19 | subject: 'subject', 20 | body: 'body', 21 | total_fee: '1' 22 | }); 23 | var sign = querystring.parse(url.split('?')[1])['sign']; 24 | assert.equal(sign, 'e135712a2e345760594831d16124f1b7'); 25 | }) 26 | 27 | it('#verify', function () { 28 | alipay.verify({ 29 | service: 'create_direct_pay_by_user', 30 | payment_type: '1', 31 | out_trade_no: 'out_trade_no', 32 | subject: 'subject', 33 | body: 'body', 34 | total_fee: '1', 35 | sign: '9b79aa313046016f8e1f45bf208cca13', 36 | }).then(function (res) { 37 | assert(res, true); 38 | }).catch(function (err) { 39 | console.error(err); 40 | }); 41 | }) 42 | }); -------------------------------------------------------------------------------- /test/app.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var express = require('express'); 3 | var bodyParser = require('body-parser'); 4 | var alipay = require('../index'); 5 | var app = express(); 6 | alipay.config({ 7 | seller_email: 'jyjjh@mail.ccnu.edu.cn', 8 | partner: '2088911275465084', 9 | key: 'tws3ri4d3sg8ohc4t7k9dnj8kumvia05', 10 | return_url: 'http://127.0.0.1:3000/return' 11 | }); 12 | 13 | // index.html 14 | app.get('/', function (req, res) { 15 | res.sendFile(__dirname + '/index.html'); 16 | }); 17 | 18 | app.use(bodyParser.urlencoded({ extended: false })); 19 | app.post('/', function (req, res) { 20 | var params = req.body; 21 | // 业务侧需要为每个订单生成一个唯一订单号 22 | params.out_trade_no = Date.now().toString() + Math.random(); 23 | var url = alipay.buildDirectPayURL(params); 24 | res.redirect(url); 25 | }); 26 | 27 | // 点击链接直接给华中师范大学贫困学生付款一元 的跳转链接 28 | app.get('/pay', function (req, res) { 29 | var url = alipay.buildDirectPayURL({ 30 | out_trade_no: Date.now().toString() + Math.random(),//业务侧需要为每个订单生成一个唯一订单号 31 | subject: '给华中师范大学贫困学生的捐赠',//订单标题 32 | body: 'body', 33 | total_fee: '1'//订单金额,单位元 34 | }); 35 | console.log(url); 36 | res.redirect(url); 37 | }); 38 | 39 | app.get('/return', function (req, res) { 40 | var params = req.query; 41 | alipay.verify(params, function (err, result) { 42 | if (err) { 43 | console.error(err); 44 | } else { 45 | if (result === true) { 46 | res.reply('支付成功'); 47 | //该通知是来自支付宝的合法通知 48 | } 49 | } 50 | }); 51 | res.end(''); 52 | }); 53 | 54 | app.listen(3000); 55 | -------------------------------------------------------------------------------- /test/index.html: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 |