由於後期的一些需求須要使用到支付寶網站支付業務,而近期又學習了 NodeJS 後端的開發,因而乎從網上找了一些資料,而支付寶開放平臺又沒有現成的 Demo 案例,也只有 NodeJS 開發的 SDK 因此,本身花了一些時間嘗試使用 NodeJS 開發一個示例 Demo 便於後面開發項目時去使用。 測試 DEMO:github.com/xiluotop/No…javascript
前端頁面
->向服務端發送訂單信息
->服務端確認信息
,向客戶端發送確認信息
->客戶端確認信息向服務端發送訂單請求
->服務端驗證訂單請求信息
->服務端像支付寶發送訂單生成
->支付寶向服務端返回訂單數據
->服務端向客戶端發送支付寶的表單信息
->客戶端跳轉到支付寶支付頁面
->客戶端支付成功
->支付寶讓客戶端同步跳轉到服務端指定的頁面
->支付寶異步通知服務端訂單支付結果
->服務端接收異步通知作相應的業務處理。
html
npm install alipay-sdk
const fs = require('fs');
const path = require('path');
// 這裏配置基本信息
const AlipayBaseConfig = {
appId: '', // 應用 ID
privateKey: fs.readFileSync(path.join(__dirname, './sandbox-pem/private_pem2048.txt'), 'ascii'), // 應用私鑰
alipayPublicKey: '',// 支付寶公鑰
gateway: 'https://openapi.alipaydev.com/gateway.do', // 支付寶的應用網關,此時爲沙箱環境的網關
charset:'utf-8', // 字符集編碼
version:'1.0', // 版本,默認 1.0
signType:'RSA2' // 祕鑰的解碼版本
};
module.exports = {
AlipayBaseConfig: AlipayBaseConfig, // 將配置模塊暴露供初始化調用
}
複製代碼
const AlipaySDK = require("alipay-sdk").default;
const alipayConfig = require(path.join(__dirname, './alipay_config.js')); // 先前定義好的 alipay_config.js 配置模塊
const alipay = new AlipaySDK(alipayConfig.AlipayBaseConfig)
const AlipayFormData = require('alipay-sdk/lib/form').default;
// 編寫一個建立支付訂單的函數,異步等待執行的函數
async function createOrder(goods) {
let method = 'alipay.trade.page.pay'; // 統一收單下單並支付頁面接口
// 公共參數 可根據業務須要決定是否傳入,當前不用
// let params = {
// app_id: '2016101000654289', // 應用 id
// method: method, // 調用接口
// format: 'JSON', // 返回數據
// charset: 'utf-8', // 字符編碼
// sign_type: 'RSA2', // 驗籤類型
// timestamp: getFormatDate(), // 請求時間戳
// version: '1.0', // 版本
// }
// 根據官方給的 API 文檔提供的一個參數集合
let bizContent = {
out_trade_no: Date.now(), // 根據時間戳來生成一個訂單號,
product_code: 'FAST_INSTANT_TRADE_PAY', // 商品碼,當前只支持這個
total_amount: goods.cost, // 商品價格
subject: goods.goodsName, // 商品名稱
timeout_express: '5m', // 超時時間
passback_params: JSON.stringify(goods.pack_params), // 將會返回的一個參數,可用於自定義商品信息最後作通知使用
}
const formData = new AlipayFormData(); // 獲取一個實例化對象
formData.addField('returnUrl', 'http://jiangck.com:9999/payresult'); // 客戶端支付成功後會同步跳回的地址
formData.addField('notifyUrl', 'http://jiangck.com:9999/notify.html'); // 支付寶在用戶支付成功後會異步通知的回調地址,必須在公網 IP 上才能收到
formData.addField('bizContent', bizContent); // 將必要的參數集合添加進 form 表單
// 異步向支付寶發送生成訂單請求, 第二個參數爲公共參數,不須要的話傳入空對象就行
const result = await alipay.exec(method, {}, {
formData: formData
});
// 返回訂單的結果信息
return result;
}
複製代碼
module.exports = {
createOrder: createOrder
}
複製代碼
const path = require('path');
// 用於通知驗籤
// ------配置 alipay SDK 環境
// 導入 SDK
const AlipaySDK = require("alipay-sdk").default;
// 導入配置
const alipayConfig = require(path.join(__dirname, './alipay_config.js'));
// 初始化
const alipaySdk = new AlipaySDK(alipayConfig.AlipayBaseConfig);
async function checkNotify(obj) {
const result = await alipaySdk.checkNotifySign(obj);
return result;
}
module.exports = checkNotify;
複製代碼
/* 這個自定義模塊用來進行 mysql 數據庫訂單的增長和查詢功能 */
// 引入 mysql 模塊
const mysql = require('mysql');
// 配置 mysql
const mysqlConfig = {
host: 'localhost', // 數據庫主機名
port: '3306', // 端口號
user: 'root', // 用戶名
password: '123456', // 密碼
database: 'alipay', // 數據庫名
}
// 封裝查詢函數
function selectSql(sqlstr,callback) {
// 創建數據庫鏈接
let sql = mysql.createConnection(mysqlConfig);
let result = null;
if (sql) {
sql.query(sqlstr, callback);
// 關閉數據庫鏈接
sql.end();
}
}
// 封裝添加函數
function addSql(sqlstr,callback) {
return selectSql(sqlstr,callback);
}
// 將兩個數據庫操做方法暴露
module.exports = {
selectSql: selectSql,
addSql: addSql
}
複製代碼
const path = require("path");
const bp = require('body-parser');
// 引入自定義 mysql 工具
const mysql = require(path.join(__dirname, './mysql.js'));
// 引入 express
const express = require('express');
// 獲取 express 實例對象
let app = express();
// 設置託管靜態資源
app.use(express.static(path.join(__dirname, './public')));
// 處理 post 請求參數
app.use(bp.urlencoded({
extended: false
}));
// 前端響應要建立訂單的數據對象
app.get('/payinfo', (req, res) => {
let data = req.query;
// 作一個簡單的商品判斷
if (data && (data.goodsName === '大衛龍' || data.goodsName === '冰闊咯' || data.goodsName === '雪碧' || data.goodsName === 'QQB') && data.count && data.cost) {
res.send(Object.assign(data, {
code: 200,
}));
} else {
res.setHeader('content-type', 'application/javascript');
res.send('alert("信息有誤,請從新嘗試!!!")');
}
})
// 獲取建立訂單的自定義模塊
const createOrder = require(path.join(__dirname, './createOrder.js')).createOrder;
// 獲取驗籤自定義模塊
const checkSign = require(path.join(__dirname, './checkSign.js'));
// 生成訂單請求
app.post('/createOrder', (req, res) => {
console.log(req.body.price);
req.body.pack_params = {
payName: req.body.payName,
goodsName: req.body.goodsName,
price: req.body.price,
count: req.body.count,
cost: req.body.cost,
}
async function asyncCreate() {
const result = await createOrder(req.body);
res.send(result);
}
asyncCreate();
});
// 支付的信息展現
app.get('/payresult', (req, res) => {
let htmlStr = '';
htmlStr += `<p>` + '商戶訂單號' + ': ' + req.query.out_trade_no + '</p>'
htmlStr += `<p>` + '支付寶交易訂單號' + ': ' + req.query.trade_no + '</p>'
htmlStr += `<p>` + '交易金額' + ': ' + req.query.total_amount + '¥</p>'
htmlStr += `<p>` + '交易時間' + ': ' + req.query.timestamp + '¥</p>'
htmlStr += '<h1 style:"text-align:center;">支付成功!!!<a href="./index.html">返回首頁!</a></h1>'
res.send(htmlStr);
})
app.post('/notify.html', (req, res) => {
// 輸出驗簽結果
async function checkResult(postData) {
let result = await checkSign(postData);
if (result) {
// console.log('訂單成功支付!!!請作處理')
// console.log(req.body);
let data = req.body;
let goods = JSON.parse(data.passback_params);
let sqlStr = ` insert into order_list value("${data.out_trade_no}", "${data.trade_no}", "${goods.goodsName}", ${goods.price}, ${goods.count}, ${data.total_amount}, "支付成功", "${goods.payName}"); `;
// 響應支付寶處理成功,不然支付寶會一直定時發送異步通知
res.end('success');
mysql.addSql(sqlStr)
}
}
checkResult(req.body);
})
// 查詢訂單接口
app.get('/getorder', (req, res) => {
mysql.selectSql('select * from order_list', (err, result) => {
result = Object.assign({
code: 200,
msg: '獲取成功',
list: JSON.stringify(result),
})
res.send(result);
});
})
app.listen(9999, () => {
console.log('server start with 9999...');
})
複製代碼