微信支付功能

支付功能

以下是一个Node.js调用微信支付功能并成功完成支付的代码示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
const express = require('express');
const WechatPay = require('wechatpay-node');
const bodyParser = require('body-parser');
const crypto = require('crypto');

const app = express();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));

// 配置微信支付参数
const config = {
appid: 'your_appid', // 微信appid
mchid: 'your_mchid', // 商户号
apikey: 'your_apikey' // API密钥
};

const wechatPay = new WechatPay(config);

// 生成预支付订单
async function createOrder(openid, orderInfo) {
const data = {
body: orderInfo.title,
openid: openid,
total_fee: orderInfo.amount * 100, // 单位分
out_trade_no: orderInfo.orderId,
spbill_create_ip: '127.0.0.1',
notify_url: 'https://your-domain.com/payment_notify' // 支付结果通知地址
};

try {
const result = await wechatPay.createOrder(data);
return result;
} catch (error) {
console.error('支付订单创建失败:', error);
throw error;
}
}

// 支付结果通知处理
app.post('/payment_notify', async (req, res) => {
const xmlData = req.body;
const notifyData = wechatPay.xmlToJSON(xmlData);

// 验证签名
if (!wechatPay.verifySign(notifyData)) {
res.status(400).send('签名验证失败');
return;
}

// 处理支付结果
if (notifyData.return_code === 'SUCCESS' && notifyData.result_code === 'SUCCESS') {
// 更新订单状态为支付成功
const orderId = notifyData.out_trade_no;
updateOrderStatus(orderId, 'paid')
.then(() => {
res.send('SUCCESS');
})
.catch(err => {
console.error('更新订单状态失败:', err);
res.status(500).send('更新订单状态失败');
});
} else {
res.send('SUCCESS');
}
});

// 示例:创建订单并返回支付参数
app.post('/create_order', async (req, res) => {
const { openid, orderInfo } = req.body;

try {
const order = await createOrder(openid, orderInfo);
res.json({
code: 0,
data: {
prepay_id: order.prepay_id,
timestamp: Math.floor(Date.now() / 1000).toString(),
noncestr: crypto.randomBytes(16).toString('hex'),
package: `prepay_id=${order.prepay_id}`,
sign: wechatPay.generateSign({
appid: config.appid,
noncestr: crypto.randomBytes(16).toString('hex'),
package: `prepay_id=${order.prepay_id}`,
sign_type: 'MD5',
timestamp: Math.floor(Date.now() / 1000).toString(),
mchid: config.mchid
})
}
});
} catch (error) {
res.status(500).json({
code: -1,
message: '创建订单失败'
});
}
});

// 更新订单状态
function updateOrderStatus(orderId, status) {
return new Promise((resolve, reject) => {
// 这里需要根据你的数据库实现
// 例如,使用MongoDB或MySQL更新订单状态
resolve();
});
}

// 启动服务器
const port = 3000;
app.listen(port, () => {
console.log(`服务器运行在 http://localhost:${port}`);
});

代码说明:

  1. 配置微信支付参数:需要填写你的微信appid、商户号和API密钥。

  2. 生成预支付订单:

    • createOrder函数用于生成微信支付的预支付订单。
    • 需要传入用户的openid、商品信息(包括标题、金额和订单号)。
  3. 支付结果通知处理:

    • 微信支付完成后,会回调/payment_notify接口。
    • 该接口会验证签名,并处理支付结果。
  4. 创建订单接口:

    • /create_order接口用于创建支付订单,并返回支付所需的参数。
    • 客户端可以通过这些参数调起微信支付。
  5. 更新订单状态:

    • 支付成功后,需要更新订单状态。
    • 这里需要根据你的数据库实现具体的更新逻辑。

    注意事项:

  6. 确保你的服务器可以接收微信支付的回调通知。
  7. 配置正确的回调地址(notify_url)。
  8. 确保你的服务器支持HTTPS(生产环境必须使用HTTPS)。
  9. 配置正确的API密钥和商户号。

    安装依赖:

1
npm install express wechatpay-node body-parser crypto

启动服务器:

1
node app.js

这个示例代码可以帮助你快速实现微信支付功能。根据你的实际需求,可能需要进一步调整和优化代码。

获取用户信息和登录

查看教程

在微信小程序中实现用户登录并获取用户信息的步骤如下:

小程序端代码

  1. 调用 wx.login 获取登录凭证 code

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    wx.login({
    success: (res) => {
    if (res.code) {
    // 将 code 发送到服务器
    wx.request({
    url: 'https://your-server.com/api/login', // 服务器接口地址
    method: 'POST',
    data: {
    code: res.code
    },
    success: (serverRes) => {
    // 处理服务器返回的数据
    console.log('服务器返回:', serverRes.data);
    },
    fail: (err) => {
    console.error('请求失败:', err);
    }
    });
    } else {
    console.error('登录失败:', res.errMsg);
    }
    },
    fail: (err) => {
    console.error('登录失败:', err);
    }
    });
  2. 获取用户信息 wx.getUserInfo

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    wx.getUserInfo({
    success: (res) => {
    console.log('用户信息:', res.userInfo);
    // 将用户信息发送到服务器或本地存储
    wx.setStorageSync('userInfo', res.userInfo);
    },
    fail: (err) => {
    console.error('获取用户信息失败:', err);
    }
    });

    服务器端代码(Node.js示例)

  3. 创建接口接收 code

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    const express = require('express');
    const app = express();
    const crypto = require('crypto');
    const config = require('./config'); // 包含appid和appsecret

    app.use(express.json());

    app.post('/api/login', async (req, res) => {
    const { code } = req.body;

    try {
    // 调用微信接口获取openid和session_key
    const response = await fetch(`https://api.weixin.qq.com/sns/jscode2session?appid=${config.appid}&secret=${config.appsecret}&js_code=${code}&grant_type=authorization_code`);
    const data = await response.json();

    if (data.errcode) {
    return res.status(500).json({ error: data.errmsg });
    }

    // 返回openid和session_key给小程序
    res.json({
    openid: data.openid,
    session_key: data.session_key
    });

    } catch (error) {
    console.error('服务器错误:', error);
    res.status(500).json({ error: '服务器错误' });
    }
    });

    app.listen(3000, () => {
    console.log('服务器运行在 http://localhost:3000');
    });

    注意事项

  • 用户授权:调用 wx.getUserInfo 前,需确保用户已授权。可以在页面中添加按钮,引导用户点击后进行授权。
  • 错误处理:在小程序和服务器端均需添加错误处理逻辑,确保程序健壮性。
  • 安全考虑:确保服务器接口的安全性,避免敏感信息泄露。appid和appsecret应妥善保管,不在客户端暴露。

通过以上步骤,您可以在微信小程序中实现用户登录并获取用户信息。确保每一步都正确实现,并进行充分的测试。

支付功能前后端

查看教程

在微信小程序中实现支付功能需要结合微信支付接口,整个流程包括小程序前端调用支付接口和后端服务器与微信支付系统交互。以下是完整的支付流程代码示例:


支付流程概述

  1. 小程序前端:

    • 调用 wx.requestPayment 接口发起支付请求。
    • 需要传递支付参数(如 timeStampnonceStrpackagesignTypepaySign)。
  2. 后端服务器:

    • 调用微信支付接口 unifiedorder 生成预支付交易单。
    • 返回预支付交易会话 prepay_id 给小程序。
    • 处理支付成功后的回调通知。

小程序前端代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
// pages/pay/pay.js

Page({
data: {
// 支付相关信息
orderInfo: {}
},

onLoad: function (options) {
// 获取订单信息
this.getOrderInfo();
},

// 获取订单信息
getOrderInfo: function () {
wx.request({
url: 'https://your-server.com/api/order/create', // 后端接口地址
method: 'POST',
data: {
// 传递订单相关信息
goodsId: 123,
price: 100
},
success: (res) => {
const orderInfo = res.data;
this.setData({ orderInfo });
this.initPayment(orderInfo);
},
fail: (err) => {
console.error('获取订单信息失败:', err);
}
});
},

// 初始化支付
initPayment: function (orderInfo) {
// 调用后端接口获取支付参数
wx.request({
url: 'https://your-server.com/api/pay/get-pay-params',
method: 'POST',
data: {
orderId: orderInfo.orderId
},
success: (res) => {
const payParams = res.data;
this.pay(payParams);
},
fail: (err) => {
console.error('获取支付参数失败:', err);
}
});
},

// 发起支付
pay: function (payParams) {
wx.requestPayment({
timeStamp: payParams.timeStamp,
nonceStr: payParams.nonceStr,
package: payParams.package,
signType: payParams.signType,
paySign: payParams.paySign,
success: (res) => {
console.log('支付成功:', res);
// 支付成功后跳转到成功页面
wx.navigateTo({
url: '/pages/pay-success/pay-success'
});
},
fail: (err) => {
console.error('支付失败:', err);
// 支付失败后跳转到失败页面
wx.navigateTo({
url: '/pages/pay-fail/pay-fail'
});
}
});
}
});

后端服务器代码(Node.js 示例)

1. 生成预支付交易单

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
const express = require('express');
const crypto = require('crypto');
const config = require('./config'); // 包含appid、appsecret、mch_id、key

const app = express();

// 生成随机字符串
function generateNonceStr() {
return Math.random().toString(36).substr(2, 15);
}

// 生成签名
function generateSign(params) {
const stringA = Object.keys(params)
.sort()
.map(key => `${key}=${params[key]}`)
.join('&');
const stringSignTemp = `${stringA}&key=${config.key}`;
return crypto.createHash('md5').update(stringSignTemp, 'utf8').digest('hex').toUpperCase();
}

// 创建订单接口
app.post('/api/order/create', (req, res) => {
const { goodsId, price } = req.body;
// 生成订单信息
const order = {
orderId: Date.now().toString(),
goodsId,
price,
createTime: new Date().toISOString()
};
res.json(order);
});

// 获取支付参数接口
app.post('/api/pay/get-pay-params', async (req, res) => {
const { orderId } = req.body;

try {
// 调用微信支付接口
const response = await fetch(`https://api.mch.weixin.qq.com/pay/unifiedorder`, {
method: 'POST',
headers: {
'Content-Type': 'application/xml'
},
body: `<xml>
<appid>${config.appid}</appid>
<mch_id>${config.mch_id}</mch_id>
<nonce_str>${generateNonceStr()}</nonce_str>
<body>商品描述</body>
<out_trade_no>${orderId}</out_trade_no>
<total_fee>${price * 100}</total_fee>
<spbill_create_ip>${req.ip}</spbill_create_ip>
<notify_url>${config.notify_url}</notify_url>
<trade_type>JSAPI</trade_type>
<sign>${generateSign({
appid: config.appid,
mch_id: config.mch_id,
nonce_str: generateNonceStr(),
body: '商品描述',
out_trade_no: orderId,
total_fee: price * 100,
spbill_create_ip: req.ip,
notify_url: config.notify_url,
trade_type: 'JSAPI'
})}</sign>
</xml>`
});

const data = await response.text();
const parser = new DOMParser();
const xmlDoc = parser.parseFromString(data, 'text/xml');

const returnCode = xmlDoc.querySelector('return_code').textContent;
if (returnCode === 'FAIL') {
return res.status(500).json({ error: '调用微信支付接口失败' });
}

const prepayId = xmlDoc.querySelector('prepay_id').textContent;
const payParams = {
timeStamp: Math.floor(Date.now() / 1000).toString(),
nonceStr: generateNonceStr(),
package: `prepay_id=${prepayId}`,
signType: 'MD5',
paySign: generateSign({
appId: config.appid,
timeStamp: Math.floor(Date.now() / 1000).toString(),
nonceStr: generateNonceStr(),
package: `prepay_id=${prepayId}`,
signType: 'MD5'
})
};

res.json(payParams);

} catch (error) {
console.error('服务器错误:', error);
res.status(500).json({ error: '服务器错误' });
}
});

// 支付成功回调接口
app.post('/api/pay/notify', async (req, res) => {
try {
const parser = new DOMParser();
const xmlDoc = parser.parseFromString(req.body, 'text/xml');

const returnCode = xmlDoc.querySelector('return_code').textContent;
if (returnCode === 'FAIL') {
return res.status(500).send('<xml><return_code>FAIL</return_code><return_msg>支付失败</return_msg></xml>');
}

const orderId = xmlDoc.querySelector('out_trade_no').textContent;
const transactionId = xmlDoc.querySelector('transaction_id').textContent;

// 处理支付成功逻辑(如更新订单状态)
console.log('支付成功:', { orderId, transactionId });

res.send('<xml><return_code>SUCCESS</return_code><return_msg>支付成功</return_msg></xml>');

} catch (error) {
console.error('支付回调处理失败:', error);
res.status(500).send('<xml><return_code>FAIL</return_code><return_msg>支付失败</return_msg></xml>');
}
});

app.listen(3000, () => {
console.log('服务器运行在 http://localhost:3000');
});

注意事项

  1. 配置文件:

    • 需要在 config.js 中配置微信支付的相关参数:
      1
      2
      3
      4
      5
      6
      7
      module.exports = {
      appid: 'your_appid',
      appsecret: 'your_appsecret',
      mch_id: 'your_mch_id',
      key: 'your_key', // API密钥
      notify_url: 'https://your-server.com/api/pay/notify' // 支付回调地址
      };
  2. 支付回调地址:

    • 确保 notify_url 是一个外网可访问的地址,并且配置在微信支付商户平台。
  3. 安全性:

    • 保护 appidappsecretmch_idkey 等敏感信息,不要在客户端暴露。
  4. 测试环境:

    • 在开发和测试阶段,建议使用微信支付测试环境。
  5. 支付成功后的处理:

    • 在支付成功后,后端需要更新订单状态,并处理相关逻辑(如扣减库存、发送通知等)。

通过以上代码和步骤,您可以在微信小程序中实现完整的支付功能。