轻松集成 Stripe:开发者代码示例
嘿,各位开发者同行们!如果你的应用曾经需要集成支付功能,那么 Stripe 很可能曾出现在你的视野中。它确实是个很棒的工具,但有时要把它所有东西都妥善配置好,感觉就像在和一只章鱼搏斗——触手太多,你都不知道下一步该抓哪条。
这正是这份指南的用武之地。我来这里不是为了重复官方文档(尽管它们很棒!)。我的目标是为你提供一条清晰、简洁的 Stripe 集成之路,其中包含一些常用编程语言的实用代码片段。你可以把它想象成和一位过来人朋友的轻松对话,他经历过你现在面临的困境,希望能帮你少走弯路。
为什么选择 Stripe?(以及为何正确集成至关重要)
在深入代码之前,我们先快速谈谈为什么 Stripe 是许多人的首选。它功能强大、安全可靠,并且提供了出色的开发者工具。但仅仅拥有强大的工具是不够的;你还需要有效地运用它。一个良好集成的支付系统不仅仅是收款那么简单;它关乎为你的用户提供流畅、值得信赖的体验,并为你的业务减少潜在的摩擦点。
核心要点:设置你的 Stripe 环境
首先,你需要一个 Stripe 账户。访问 stripe.com 并注册。成功注册后,你可以在开发者控制面板中找到你的 API 密钥。你有两套密钥:一套是“可发布”密钥(用于前端,可以安全地公开),另一套是“秘密”密钥(用于后端,务必保密!)。
对于本地开发,最好设置一个 .env
文件来存储你的秘密密钥。切勿将其硬编码!
.env
文件示例:
STRIPE_SECRET_KEY=sk_test_YOUR_SECRET_KEY
STRIPE_PUBLISHABLE_KEY=pk_test_YOUR_PUBLISHABLE_KEY
创建一个基本的支付会话
如今,使用 Stripe 处理支付最常见的方式是通过 Checkout Sessions。这能将大量的 PCI 合规性和用户界面样式的工作分流给 Stripe,这对于我们开发者来说是巨大的福音。
你的前端只需将用户重定向到 Stripe 托管的页面,支付完成后,用户将被重定向回你的网站。
以下是如何从后端发起一个支付会话:
Node.js 示例(使用 express
):
// backend/server.js
const express = require('express');
const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);
const app = express();
app.use(express.json()); // 用于解析 application/json
app.post('/create-checkout-session', async (req, res) => {
try {
const session = await stripe.checkout.sessions.create({
payment_method_types: ['card'],
line_items: [
{
price_data: {
currency: 'usd',
product_data: {
name: 'Awesome Product',
},
unit_amount: 2000, // $20.00
},
quantity: 1,
},
],
mode: 'payment',
success_url: 'http://localhost:3000/success?session_id={CHECKOUT_SESSION_ID}',
cancel_url: 'http://localhost:3000/cancel',
});
res.json({ id: session.id });
} catch (error) {
console.error('Error creating checkout session:', error);
res.status(500).json({ error: error.message });
}
});
app.listen(4242, () => console.log('Node server listening on port 4242!'));
Python 示例(使用 Flask
):
# backend/app.py
from flask import Flask, jsonify, request, redirect, url_for
import stripe
import os
app = Flask(__name__)
stripe.api_key = os.getenv('STRIPE_SECRET_KEY')
@app.route('/create-checkout-session', methods=['POST'])
def create_checkout_session():
try:
session = stripe.checkout.Session.create(
payment_method_types=['card'],
line_items=[
{
'price_data': {
'currency': 'usd',
'product_data': {
'name': 'Awesome Product',
},
'unit_amount': 2000,
},
'quantity': 1,
}
],
mode='payment',
success_url='http://localhost:3000/success?session_id={CHECKOUT_SESSION_ID}',
cancel_url='http://localhost:3000/cancel',
)
return jsonify(id=session.id)
except Exception as e:
print(f'Error creating checkout session: {e}')
return jsonify(error=str(e)), 500
if __name__ == '__main__':
app.run(port=4242)
在前端,调用此端点后,你将重定向用户:
前端示例(使用 Stripe.js
):
<!-- frontend/index.html -->
<!DOCTYPE html>
<html>
<head>
<title>购买我的超赞产品</title>
<script src="https://js.stripe.com/v3/"></script>
</head>
<body>
<h1>购买我的超赞产品</h1>
<button id="checkout-button">立即支付</button>
<script type="text/javascript">
const stripe = Stripe('pk_test_YOUR_PUBLISHABLE_KEY'); // 替换为你的公开密钥
const checkoutButton = document.getElementById('checkout-button');
checkoutButton.addEventListener('click', async () => {
try {
const response = await fetch('/create-checkout-session', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
});
const session = await response.json();
if (session.id) {
const result = await stripe.redirectToCheckout({
sessionId: session.id,
});
if (result.error) {
alert(result.error.message);
}
} else if (session.error) {
alert(session.error.message);
}
} catch (error) {
console.error('Error initiating checkout:', error);
alert('无法发起支付。请重试。');
}
});
</script>
</body>
</html>
处理支付后事件:Webhook 是你的好帮手
支付成功后,你的后端如何知道发生了什么?你不能仅仅依赖 success_url
,因为用户可能会关闭浏览器。答案是 webhooks。
每当发生重要事件(例如支付成功、退款、订阅更新等)时,Stripe 都会向你指定的 webhook 端点发送事件。你的服务器会监听这些事件并采取相应的行动。
设置 Webhook 端点
首先,你需要一个公共 URL,供 Stripe 向其发送事件。对于本地开发,ngrok
等工具非常宝贵。它们可以从公共 URL 到你的本地机器创建安全隧道。查阅 ngrok
的文档以进行设置。
ngrok
运行后,你通常会像 ngrok http 4242
这样启动它(假设你的服务器运行在 4242 端口)。它会给你一个公共 URL(例如 https://your-random-subdomain.ngrok-free.app
)。
现在,在你的 Stripe 控制面板中,前往“开发者” > “Webhooks”并点击“添加端点”。粘贴你的 ngrok
URL(例如 https://your-random-subdomain.ngrok-free.app/webhook
),并选择你要监听的事件(checkout.session.completed
是支付事件的一个好的开始)。
验证 Webhook 签名
验证 webhook 签名绝对至关重要。这能确保事件确实来自 Stripe,并且未被篡改。
Stripe 在 Stripe-Signature
头部中包含了一个签名。你需要你的 webhook 秘密(在 Stripe 控制面板的 webhook 端点详细信息中可以找到)来验证它。
Node.js Webhook 示例:
// backend/server.js (添加到你现有的 server.js)
// 重要:确保此端点是专用的,并且在使用 body-parser 或 express.json 全局解析 JSON 之前,
// 因为 webhooks 需要原始的请求体。
app.post('/webhook', express.raw({type: 'application/json'}), async (req, res) => {
const sig = req.headers['stripe-signature'];
let event;
const endpointSecret = process.env.STRIPE_WEBHOOK_SECRET; // 从你的 Stripe webhook 设置中获取
try {
event = stripe.webhooks.constructEvent(req.body, sig, endpointSecret);
} catch (err) {
console.error(`Webhook Error: ${err.message}`);
return res.status(400).send(`Webhook Error: ${err.message}`);
}
// 处理事件
switch (event.type) {
case 'checkout.session.completed':
const checkoutSession = event.data.object;
// 完成购买,更新你的数据库,发送确认邮件等。
console.log(`Checkout session completed for: ${checkoutSession.id}`);
// 从 checkoutSession 对象中访问客户、订单项等
break;
// ... 处理其他事件类型
default:
console.log(`Unhandled event type ${event.type}`);
}
// 返回 200 响应以确认收到事件
res.send();
});
Python Webhook 示例:
# backend/app.py (添加到你现有的 app.py)
@app.route('/webhook', methods=['POST'])
def webhook_received():
request_data = request.data.decode('utf-8')
signature = request.headers.get('stripe-signature')
webhook_secret = os.getenv('STRIPE_WEBHOOK_SECRET') # 从你的 Stripe webhook 设置中获取
try:
event = stripe.Webhook.construct_event(
payload=request_data,
sig_header=signature,
secret=webhook_secret
)
except ValueError as e:
# 无效的载荷
print(f'Invalid payload: {e}')
return jsonify({'error': 'Invalid payload'}), 400
except stripe.error.SignatureVerificationError as e:
# 无效的签名
print(f'Invalid signature: {e}')
return jsonify({'error': 'Invalid signature'}), 400
# 处理事件
if event['type'] == 'checkout.session.completed':
checkout_session = event['data']['object']
# 完成购买,更新你的数据库,发送确认邮件等。
print(f'Checkout session completed for: {checkout_session.id}')
# ... 处理其他事件类型
return jsonify({'status': 'success'}), 200
几个需要牢记的快速最佳实践
- 错误处理至关重要: 始终将你的 Stripe API 调用放在
try...catch
块中。支付是关键环节,你希望能够优雅地处理任何可能出错的情况。 - 幂等性: 在进行 API 调用时(尤其是那些创建资源如收款的调用),使用幂等键。这确保了即使请求意外地多次发送(例如,由于网络故障),Stripe 也只会处理一次。大多数客户端库会为你处理这个问题,但了解一下是有好处的。
- 测试模式与实时模式: 始终在
test
模式下进行充分的开发和测试。使用 Stripe 提供的测试卡号。仅在你完全准备好进行真实交易时,才切换到live
模式密钥。 - HTTPS 不可妥协: 对于实时应用,务必确保你的域名使用 HTTPS。这可以保护敏感的支付信息。
- 仅存储你需要的信息: 避免在你的服务器上存储敏感的银行卡详细信息。让 Stripe 处理这些。如果你需要引用客户或支付方式,使用 Stripe 的客户 ID 或支付方式 ID。
总结
Stripe 是一个强大得令人难以置信的平台,集成它不一定是一项艰巨的任务。通过将其分解为可管理的步骤——设置密钥、创建支付会话以及至关重要的处理 Webhooks——你可以相当顺利地部署你的支付流程。
请记住,这只是一个开始。Stripe 提供了更多功能:订阅、发票、关联账户以及更复杂的支付流程。但有了这些基础知识,你就能很好地在应用程序中构建强大而可靠的支付处理功能。祝编程愉快!