在 Node.js 中实现支付网关集成
引言:支付网关是什么?
大家好,欢迎来到今天的讲座!今天我们要聊的是如何在 Node.js 中实现支付网关的集成。如果你是第一次接触这个话题,别担心,我会尽量用轻松诙谐的语言,带你一步步了解支付网关的工作原理,并教你如何在 Node.js 项目中实现它。
首先,什么是支付网关?简单来说,支付网关就像是你和银行之间的“桥梁”。当你在网上购物时,点击“支付”按钮后,你的信用卡信息并不会直接发送到商家的服务器,而是通过支付网关进行处理。支付网关会验证你的支付信息,确保它是安全的,并将结果返回给商家。这样做的好处是,商家不需要自己处理敏感的支付信息,从而减少了安全风险。
支付网关通常由第三方公司提供,比如 PayPal、Stripe、Square 等。这些公司提供了 API(应用程序编程接口),开发者可以通过这些 API 将支付功能集成到自己的应用中。今天我们主要讨论的是如何使用 Stripe 的 API 来实现支付网关集成。
为什么选择 Stripe?
在众多支付网关中,为什么我们选择了 Stripe?其实原因很简单:
- 易于集成:Stripe 提供了非常详细的文档和丰富的 SDK,几乎支持所有的主流编程语言,包括 Node.js。
- 全球支持:Stripe 支持全球 135+ 个国家/地区的支付,涵盖了多种货币和支付方式。
- 安全性:Stripe 符合 PCI DSS 标准,这意味着它已经通过了严格的安全审查,开发者无需担心支付信息的安全问题。
- 灵活性:除了基本的支付功能,Stripe 还提供了订阅、发票、退款等高级功能,适合各种业务需求。
当然,其他支付网关也有各自的优点,但考虑到我们的主题是 Node.js,Stripe 的 Node.js SDK 无疑是最好的选择之一。
准备工作
在开始编写代码之前,我们需要做一些准备工作。首先是安装必要的工具和库。
1. 安装 Node.js 和 npm
如果你还没有安装 Node.js 和 npm(Node Package Manager),请先去官网下载并安装最新版本。安装完成后,你可以通过以下命令检查是否安装成功:
node -v
npm -v
如果看到版本号,说明安装成功!
2. 创建一个新的 Node.js 项目
接下来,创建一个新的 Node.js 项目。打开终端,进入你想要存放项目的文件夹,然后运行以下命令:
mkdir payment-gateway-integration
cd payment-gateway-integration
npm init -y
这将会创建一个名为 payment-gateway-integration
的文件夹,并在其中生成一个 package.json
文件。-y
参数会自动为你生成默认的配置,省去了手动输入的麻烦。
3. 安装 Stripe SDK
现在我们来安装 Stripe 的官方 Node.js SDK。运行以下命令:
npm install stripe
安装完成后,你就可以在项目中使用 Stripe 的 API 了。
4. 获取 Stripe API 密钥
要使用 Stripe 的 API,你需要一个 API 密钥。登录 Stripe Dashboard,进入开发者设置页面,找到“API keys”部分。你会看到两个密钥:Publishable key
和 Secret key
。
- Publishable key:用于前端,允许你在浏览器中与 Stripe 交互,例如收集支付信息。
- Secret key:用于后端,允许你在服务器上处理支付请求。注意:永远不要将 Secret key 暴露在前端代码中!
将这两个密钥保存在一个安全的地方,稍后我们会用到它们。
实现支付网关的基本流程
好了,准备工作完成了,接下来我们来看看如何实现支付网关的基本流程。整个流程可以分为以下几个步骤:
- 前端:收集支付信息
- 后端:创建支付意图
- 前端:确认支付
- 后端:处理支付结果
1. 前端:收集支付信息
在前端,我们需要收集用户的支付信息。为了确保支付信息的安全性,我们不会直接将信用卡信息发送到服务器,而是通过 Stripe 的 JavaScript SDK 来处理。Stripe 提供了一个叫做 Elements 的组件,可以帮助我们轻松地构建安全的支付表单。
首先,在 public
文件夹中创建一个 HTML 文件,命名为 index.html
,并在其中引入 Stripe 的 JavaScript SDK:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Payment Gateway Integration</title>
<script src="https://js.stripe.com/v3/"></script>
</head>
<body>
<h1>Checkout</h1>
<form id="payment-form">
<div id="card-element"><!-- Stripe Elements will be inserted here --></div>
<button id="submit">Pay</button>
</form>
<script>
// Initialize Stripe with your publishable key
const stripe = Stripe('your-publishable-key');
// Create an instance of Elements
const elements = stripe.elements();
// Create a card element and mount it to the DOM
const cardElement = elements.create('card');
cardElement.mount('#card-element');
// Handle form submission
document.getElementById('payment-form').addEventListener('submit', async (event) => {
event.preventDefault();
// Create a PaymentMethod object
const { error, paymentMethod } = await stripe.createPaymentMethod({
type: 'card',
card: cardElement,
});
if (error) {
console.error(error);
} else {
// Send the payment method ID to the server
fetch('/create-payment-intent', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ paymentMethodId: paymentMethod.id }),
})
.then(response => response.json())
.then(data => {
if (data.clientSecret) {
confirmPayment(data.clientSecret);
}
});
}
});
// Confirm the payment
async function confirmPayment(clientSecret) {
const { error } = await stripe.confirmCardPayment(clientSecret, {
payment_method: { card: cardElement },
});
if (error) {
console.error(error);
} else {
alert('Payment successful!');
}
}
</script>
</body>
</html>
在这段代码中,我们做了几件重要的事情:
- 使用
Stripe('your-publishable-key')
初始化 Stripe。 - 使用
elements.create('card')
创建一个卡元素,并将其挂载到页面上的#card-element
元素中。 - 当用户提交表单时,调用
stripe.createPaymentMethod
创建一个支付方法对象,并将其发送到服务器。 - 最后,使用
stripe.confirmCardPayment
确认支付。
2. 后端:创建支付意图
在前端收集完支付信息后,我们需要在后端创建一个支付意图(Payment Intent)。支付意图是 Stripe 的核心概念之一,它表示一次支付的意图,并包含了支付的状态和相关信息。
在 server.js
文件中,编写以下代码:
const express = require('express');
const stripe = require('stripe')('your-secret-key');
const app = express();
app.use(express.json());
// Endpoint to create a PaymentIntent
app.post('/create-payment-intent', async (req, res) => {
try {
const { paymentMethodId } = req.body;
// Create a PaymentIntent with the received payment method ID
const paymentIntent = await stripe.paymentIntents.create({
amount: 1000, // Amount in cents (e.g., $10.00)
currency: 'usd',
payment_method: paymentMethodId,
confirm: true, // Automatically confirm the payment
});
res.json({ clientSecret: paymentIntent.client_secret });
} catch (error) {
res.status(500).json({ error: error.message });
}
});
// Start the server
app.listen(3000, () => {
console.log('Server is running on port 3000 🚀');
});
在这段代码中,我们做了以下几件事:
- 使用
stripe.paymentIntents.create
创建一个支付意图,并传入从前端接收到的支付方法 ID。 - 设置
amount
和currency
,分别表示支付金额和货币类型。注意,金额是以最小单位(如美分)表示的,因此$10.00
应该写成1000
。 - 设置
confirm: true
,表示我们希望 Stripe 自动确认这次支付。 - 返回
client_secret
,这是前端确认支付时需要的凭据。
3. 前端:确认支付
当后端返回 client_secret
后,前端会调用 stripe.confirmCardPayment
来确认支付。这个过程实际上是通过 Stripe 的 API 与支付网关进行通信,确保支付顺利完成。
在之前的前端代码中,我们已经实现了 confirmPayment
函数,它会接收 client_secret
并调用 stripe.confirmCardPayment
。如果支付成功,用户会看到一个弹窗提示;如果失败,则会在控制台中输出错误信息。
4. 后端:处理支付结果
支付完成后,我们通常还需要在后端处理支付结果。例如,更新订单状态、发送确认邮件等。为了实现这一点,我们可以监听 Stripe 的 Webhook 事件。
配置 Webhook
Stripe 提供了一种称为 Webhook 的机制,允许我们在支付事件发生时接收通知。我们需要在 Stripe Dashboard 中配置 Webhook,告诉 Stripe 将事件发送到我们的服务器。
- 登录 Stripe Dashboard,进入开发者设置页面,找到“Webhooks”部分。
- 点击“Add endpoint”,输入你的服务器 URL(例如
http://localhost:3000/webhook
)。 - 选择你感兴趣的事件类型,例如
payment_intent.succeeded
和payment_intent.payment_failed
。
处理 Webhook 事件
在 server.js
中添加一个路由来处理 Webhook 事件:
const bodyParser = require('body-parser');
const crypto = require('crypto');
// Middleware to parse raw request body for Webhook
app.use(
'/webhook',
bodyParser.raw({ type: 'application/json' })
);
// Webhook endpoint
app.post('/webhook', async (req, res) => {
const sig = req.headers['stripe-signature'];
const endpointSecret = 'your-webhook-secret'; // Get this from Stripe Dashboard
let event;
try {
event = stripe.webhooks.constructEvent(req.body, sig, endpointSecret);
} catch (err) {
return res.status(400).send(`Webhook Error: ${err.message}`);
}
// Handle different types of events
switch (event.type) {
case 'payment_intent.succeeded':
const paymentIntent = event.data.object;
console.log('Payment succeeded:', paymentIntent);
// Update order status, send confirmation email, etc.
break;
case 'payment_intent.payment_failed':
const failedIntent = event.data.object;
console.log('Payment failed:', failedIntent);
// Notify user, log error, etc.
break;
default:
console.log(`Unhandled event type ${event.type}`);
}
res.json({ received: true });
});
在这段代码中,我们做了以下几件事:
- 使用
bodyParser.raw
解析原始请求体,因为 Webhook 请求是以 JSON 格式发送的。 - 使用
stripe.webhooks.constructEvent
验证 Webhook 签名,确保请求来自 Stripe。 - 根据不同的事件类型(如
payment_intent.succeeded
或payment_intent.payment_failed
),执行相应的逻辑。
高级功能:订阅和退款
除了基本的支付功能,Stripe 还提供了许多高级功能,例如订阅和退款。下面我们简要介绍一下如何实现这些功能。
订阅
订阅是一种常见的商业模式,适用于按月或按年收费的服务。Stripe 提供了强大的订阅管理功能,允许你轻松地创建和管理订阅计划。
创建订阅计划
首先,我们需要在 Stripe Dashboard 中创建一个订阅计划。进入“Billing” -> “Products & prices”,点击“Create product”,然后为产品添加价格计划。你可以选择按月或按年收费,并设置具体的金额和货币。
创建订阅
在后端,我们可以使用 stripe.subscriptions.create
来创建一个订阅。以下是一个简单的示例:
app.post('/create-subscription', async (req, res) => {
try {
const { customerId, priceId } = req.body;
const subscription = await stripe.subscriptions.create({
customer: customerId,
items: [{ price: priceId }],
expand: ['latest_invoice.payment_intent'],
});
res.json({ subscription });
} catch (error) {
res.status(500).json({ error: error.message });
}
});
在这个例子中,我们传入了 customerId
和 priceId
,分别表示客户 ID 和订阅计划的价格 ID。Stripe 会根据这些信息创建一个订阅,并返回订阅对象。
退款
有时,用户可能会要求退款。Stripe 也提供了简单的 API 来处理退款。以下是一个退款的示例:
app.post('/refund-payment', async (req, res) => {
try {
const { paymentIntentId } = req.body;
const refund = await stripe.refunds.create({
payment_intent: paymentIntentId,
});
res.json({ refund });
} catch (error) {
res.status(500).json({ error: error.message });
}
});
在这个例子中,我们传入了 paymentIntentId
,表示要退款的支付意图 ID。Stripe 会根据这个 ID 执行退款操作,并返回退款对象。
总结
通过今天的讲座,我们学习了如何在 Node.js 中实现支付网关集成。我们从基础知识开始,逐步介绍了如何使用 Stripe 的 API 创建支付意图、处理支付结果、配置 Webhook 以及实现订阅和退款等功能。希望这些内容对你有所帮助!
如果你有任何问题或建议,欢迎在评论区留言。感谢大家的参与,下次再见! 😊
附录:常用 API 参考表
API 方法 | 描述 | 示例 |
---|---|---|
stripe.paymentIntents.create |
创建支付意图 | stripe.paymentIntents.create({ amount: 1000, currency: 'usd' }) |
stripe.paymentMethods.create |
创建支付方法 | stripe.paymentMethods.create({ type: 'card', card: cardElement }) |
stripe.confirmCardPayment |
确认支付 | stripe.confirmCardPayment(clientSecret) |
stripe.subscriptions.create |
创建订阅 | stripe.subscriptions.create({ customer: 'cus_123', items: [{ price: 'price_456' }] }) |
stripe.refunds.create |
创建退款 | stripe.refunds.create({ payment_intent: 'pi_789' }) |
Q&A
问:我可以在生产环境中使用测试模式吗?
答:不建议在生产环境中使用测试模式。测试模式仅用于开发和调试,所有交易都是模拟的,不会真正扣款。在上线前,请务必切换到生产模式,并确保你已经准备好处理真实的支付请求。
问:如何处理支付失败的情况?
答:支付失败时,Stripe 会返回一个错误对象,包含详细的错误信息。你可以在前端捕获这些错误,并根据具体情况采取相应的措施,例如提示用户重新输入支付信息或联系客服。
问:Stripe 支持哪些支付方式?
答:Stripe 支持多种支付方式,包括信用卡、借记卡、Apple Pay、Google Pay、支付宝、微信支付等。具体支持的支付方式取决于你所在的国家和地区。你可以在 Stripe Dashboard 中查看完整的支付方式列表。