📖 前言 · 你会学到什么
这份指南给独立开发者 / 个人产品用:不用建数据库、不用做完整会员系统,也能安全验证"这个人真的付过款"。全程可以用 Stripe 的测试模式完成,不需要真实信用卡、不需要公司资质。
七节,按顺序读一遍就能跑通
- ① 为什么"前端记一个已付款标记"能被绕过,而 session_id 验证不能
- ② Stripe 测试模式怎么用——不花一分钱、不需要公司资质就能跑通全流程
- ③ Publishable Key 和 Secret Key 的区别,哪个能放前端、哪个绝对不能
- ④ Payment Link(免代码收银台)怎么建,最容易漏掉的"付款后重定向"设置
- ⑤ session_id 验证的原理 + 最简后端代码示例
- ⑥ 测试信用卡号 + 一份"验证失败了先查这几个地方"的排错清单
- ⑦ 术语表(带 🔊 发音)
内容仅为教程说明,不构成金融 / 法律建议。
① 为什么不能只信前端说的"我付过款了"
很多人第一版收款功能是这样做的:用户点"购买"→ 跳到 Stripe 付款页 → 付完款跳回来 → 网页显示"感谢购买,这是你的内容"。
问题在哪
如果"显示感谢页 + 解锁内容"这件事只是前端代码判断一个网址参数(比如网址里有没有 ?thanks=1),任何人打开浏览器"开发者工具",或者直接手动打这个网址,都能绕过付款直接看到"已解锁"的画面——前端的任何判断逻辑,用户都能看到、都能改。
正确思路
真正安全的做法:付款成功后,Stripe 会给这次交易一个独一无二、无法伪造的凭证(session_id)。你的网页拿着这个凭证,去问 Stripe 官方服务器本身"这个 session_id 对应的交易,真的付款成功了吗",官方说"是"才解锁内容。这个问题的核心不是"要不要写代码判断",而是"由谁来判断、判断的依据是不是能被用户伪造"。
这份指南接下来会一步步带你搭好这套验证,全程可以用 Stripe 的"测试模式"完成,不需要真实信用卡、不需要公司资质。
② Stripe 是什么,为什么先用"测试模式"不用怕
Stripe = 一个专门帮网站收信用卡钱的服务商。你不用自己懂银行卡合规,注册账号后它给你一个"收款链接/收款页面",顾客填卡号付钱,钱到你的 Stripe 账户,你再提现到银行卡。
测试模式(Test mode)
Stripe 账号一注册就自带一个"假环境",专门给开发阶段用——所有操作和正式收款完全一样,但用的是假信用卡号,不会真的扣钱、不需要公司资质、不需要通过审核。开发/测试阶段应该先用测试模式跑通全部流程,确认没问题了再切换到正式模式(正式模式要补充银行账户/身份信息,是后面的事,现在不用管)。
Stripe 后台左上角(或右上角)有一个开关,显示"测试模式"/"Test mode",确保它是打开的(通常新注册默认就是打开的)。
③ 注册 + 拿到 API Key
- 去
stripe.com注册一个账号(邮箱+密码即可,不需要马上填公司信息) - 登录后,左侧菜单找 "开发者"(Developers) → "API密钥"(API keys)
- 会看到两个 Key:
Key 能不能公开 用途 Publishable key( pk_test_...开头)✅ 可以放前端代码,公开也没关系 前端展示付款按钮时用 Secret key( sk_test_...开头)❌ 绝对不能放前端/公开仓库 后端服务器用来核实交易,只能存在服务器/后端进程里 - 点"Secret key"旁边的"显示/Reveal",复制这一串,妥善保存(不要贴到聊天记录、不要提交到公开代码仓库)
- 把它写进你后端项目的环境变量文件(通常叫
.env),变量名常见写法是STRIPE_SECRET_KEY=sk_test_你的真实值
.env 这类文件不能公开:几乎所有正规项目都用这种"环境变量文件"存密钥,规矩是这个文件永远不会被上传到 GitHub 这类公开平台,只留在你自己的服务器/电脑上。如果你的代码托管在 Git 仓库,记得把它加进 .gitignore。④ 给每个商品建一个"付款链接"(Payment Link)
Payment Link = 一个现成的付款网页,Stripe 帮你做好,你不用自己写收银台代码。
- Stripe 后台左侧菜单找 "付款链接"(Payment Links)
- 点"新建"(Create payment link)
- 填商品名字、价格(测试模式随便填,比如 $9.99)
- 建好后会给你一个网址,形如
https://buy.stripe.com/xxxxxxxx——每个商品各建一个
⚠️ 最容易漏掉的一步:付款后重定向
默认情况下,Stripe 付款成功后会显示它自己的一个通用感谢页,不会跳回你的网站——这样你的网站就拿不到"这个人确实付过款"的证据。必须手动改成跳回你自己的网页:
- 回到刚才建的 Payment Link,点进去 → 找"编辑"(Edit)
- 找到 "付款后"(After payment) 这个设置区
- 选 "重定向客户到您的网站"(Redirect customers to your website)(不要选默认的"显示确认页")
- 网址栏填(把
your-product-id换成你自己代码里给这个商品定的固定编号,{CHECKOUT_SESSION_ID}要原样打进去,包括花括号):https://yoursite.com/thank-you?pid=your-product-id&session_id={CHECKOUT_SESSION_ID}
{CHECKOUT_SESSION_ID} 是一个"占位符"。类比成一张预先印好的表格,上面印着"姓名:______"这样一个空格——你只负责把这个空格模板准备好,真正往上面"写字"的是 Stripe:每次有人真的完成付款,Stripe 会把这次付款一个独一无二的编号(真实的 session ID,一长串字母数字)自动替换进这个花括号的位置,再把整个网址发给顾客的浏览器。你不需要自己去找这个值该填什么——只要把 {CHECKOUT_SESSION_ID} 这几个字原样打进 Stripe 后台的设置框里,"自动填空"是 Stripe 自己做的。
⑤ 为什么 session_id 验证不能被伪造
拿到网址里的 session_id 后,你的后端要做一件事:拿着这个 session_id,调用 Stripe 官方 SDK 提供的接口(比如 Node.js 里的 stripe.checkout.sessions.retrieve(session_id)),去问 Stripe 官方服务器"这笔交易的付款状态是什么",Stripe 会诚实地返回 payment_status 字段,值是 paid 才算真正付款成功。
为什么这个方法不能被绕过
session_id 是 Stripe 服务器在真实付款流程中生成的,前端拿不到别人的、也编不出一个能通过 Stripe 官方核实的假 id。这跟"前端自己声明一个 已付款=true 的标记"完全不同——那种标记用户用浏览器开发者工具就能直接改成 true,而 session_id 的核实过程发生在你自己的服务器和 Stripe 服务器之间,用户的浏览器完全碰不到、看不到这一步。
最简后端逻辑(Node.js 示例,说明用,非完整代码)
const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);
app.get('/api/verify-purchase', async (req, res) => {
const { session_id } = req.query;
if (!session_id) return res.json({ verified: false, reason: 'missing_session_id' });
try {
const session = await stripe.checkout.sessions.retrieve(session_id);
const verified = session.payment_status === 'paid';
res.json({ verified });
} catch (err) {
res.json({ verified: false, reason: 'session_not_found' });
}
});
前端在展示"感谢页/解锁内容"之前,先调用这个接口确认 verified: true,再决定要不要显示付费内容或触发下一步动作(比如生成内容、发放下载链接)。
⑥ 怎么测试(不花一分钱)+ 排错清单
测试信用卡号
| 卡号 | 结果 |
|---|---|
4242 4242 4242 4242 | 模拟付款成功 |
4000 0000 0000 0002 | 模拟"被拒绝" |
有效期填任意未来日期(比如 12/34),CVC 填任意3位数(比如 123),姓名/邮编随便填。
完整测试流程
打开你的网页 → 点击购买 → 跳到 Stripe 付款页 → 用上面的测试卡号付款 → 应该会自动跳回你设置的重定向地址(带着真实的 session_id)→ 你的网页调用验证接口 → 显示"已验证付款"。
怎么确认后端配置对不对(不用真的走一遍付款也能查)
直接访问一次你的验证接口,随便传一个假的 session_id(比如 ?session_id=test),观察返回内容:
| 返回内容 | 说明 |
|---|---|
{"verified":false,"reason":"stripe_not_configured"} | Secret Key 还没填/没生效,后端需要重启(改了 .env 必须重启才生效) |
{"verified":false,"reason":"session_not_found"} | 这说明 Key 填对了、后端真的连上了 Stripe 官方服务器(只是这个假 session_id 在 Stripe 那边查不到,这是正常的,因为它本来就是编的) |
如果真实付款走完流程还是验证失败,先怀疑这几个地方
- 后端环境变量里的 Secret Key 是不是真的存进去了、有没有打错、有没有重启后端
- Payment Link 的"After payment"是不是真的设成了"重定向",
{CHECKOUT_SESSION_ID}有没有连花括号一起打进去 - 商品编号(
pid这类参数)对不对应 - 后端服务本身是不是真的在运行(可以直接打开验证接口的网址看有没有反应)
⑦ 术语表
- Stripe
- 一家专门帮网站/App处理信用卡收款的第三方支付服务商。
- Payment Link
- Stripe 提供的免代码收银台,生成一个网址,顾客打开就能付款,不用自己搭建收银流程。
- Publishable Key / Secret Key
- Publishable Key 可以公开放前端;Secret Key 是真正的密钥,只能放在服务器/后端,绝不能出现在前端代码里。
- Session ID
- Stripe 在一次付款交易中生成的唯一凭证,用来向 Stripe 官方核实这笔交易是否真的付款成功。
- Webhook
- 本指南用的是"用户跳转回网站时携带 session_id"的验证方式,更进阶的做法是让 Stripe 主动通知你的服务器(Webhook),适合不依赖用户浏览器跳转、更稳健的生产环境场景,可作为后续升级方向。
- .env 文件
- 专门用来存密钥/密码这类不能公开配置的文件,规矩是永远不上传到公开代码仓库。