如何在自有网站实现Stripe发票用户下载功能?
获取Stripe订阅发票下载URL的技术方案
嘿,这个需求我之前做过好几次,其实Stripe已经给我们提供了很直接的解决办法,不用自己折腾生成PDF。下面分两种常用方案给你讲,你可以根据自己的场景选:
方案一:在Webhook接收时提前存储PDF URL(推荐)
既然你已经在用Webhook把发票数据存到数据库了,那最省心的方式就是在Webhook触发时直接把Stripe生成的发票PDF URL一起存下来,这样后面给用户展示账单时直接从数据库取就行,不用再额外调用Stripe API。
具体步骤:
- 在处理
invoice.paid的Webhook事件时,从Stripe返回的invoice对象里拿到invoice_pdf字段,这就是该发票的直接下载URL。 - 把这个URL和其他发票数据(比如invoice_id、金额、日期)一起存入你的数据库账单表中。
示例代码(Node.js + Stripe SDK):
const stripe = require('stripe')('你的Stripe秘钥'); // 假设你用Express处理Webhook app.post('/stripe-webhook', express.raw({type: 'application/json'}), async (req, res) => { const sig = req.headers['stripe-signature']; let event; try { event = stripe.webhooks.constructEvent( req.body, sig, '你的Webhook签名秘钥' ); } catch (err) { return res.status(400).send(`Webhook Error: ${err.message}`); } // 只处理已支付的发票事件 if (event.type === 'invoice.paid') { const invoice = event.data.object; // 把发票数据存入数据库,重点保存invoice_pdf await yourDatabase.query( 'INSERT INTO user_invoices (invoice_id, pdf_url, customer_id, amount, created_at) VALUES (?, ?, ?, ?, ?)', [invoice.id, invoice.invoice_pdf, invoice.customer, invoice.amount_paid, new Date(invoice.created * 1000)] ); } res.json({received: true}); });
这样一来,当你在前端展示用户的账单记录时,直接从数据库取出pdf_url,给下载按钮设置这个链接就行:
<!-- 前端示例(比如React) --> <button onClick={() => window.open(invoice.pdfUrl, '_blank')}> 下载发票 </button>
方案二:实时调用Stripe API获取PDF URL
如果因为某些原因没法提前存储URL(比如之前的Webhook没存这个字段,不想改历史数据),那可以通过后端实时调用Stripe的Retrieve Invoice API来获取invoice_pdf字段。
注意:
绝对不能在前端直接调用Stripe API!会暴露你的秘钥,必须通过后端中转。
后端示例(Node.js):
// 后端接口,用于获取指定invoice_id的PDF URL app.get('/api/user/invoices/:invoiceId/pdf', async (req, res) => { try { // 先验证当前登录用户是否有权限访问这个发票(重要!防止越权) const userId = req.user.id; // 假设你用了用户认证中间件 const invoiceRecord = await yourDatabase.query( 'SELECT * FROM user_invoices WHERE invoice_id = ? AND user_id = ?', [req.params.invoiceId, userId] ); if (!invoiceRecord) { return res.status(403).json({error: '无权访问该发票'}); } // 调用Stripe API获取发票详情 const stripeInvoice = await stripe.invoices.retrieve(req.params.invoiceId); // 返回PDF URL给前端 res.json({pdfUrl: stripeInvoice.invoice_pdf}); } catch (error) { res.status(500).json({error: '获取发票链接失败:' + error.message}); } });
前端调用示例:
const handleDownloadInvoice = async (invoiceId) => { try { const response = await fetch(`/api/user/invoices/${invoiceId}/pdf`); const data = await response.json(); // 触发下载 const aTag = document.createElement('a'); aTag.href = data.pdfUrl; aTag.download = `invoice-${invoiceId}.pdf`; // 指定下载后的文件名 document.body.appendChild(aTag); aTag.click(); document.body.removeChild(aTag); } catch (err) { alert('下载失败,请稍后重试'); console.error(err); } };
关键注意事项
- 权限控制:不管用哪种方案,都要确保只有发票所属的用户才能获取下载链接,绝对不能让任意用户通过invoice_id拿到其他人的发票。
- 发票状态:只有
paid状态的发票才会生成invoice_pdf,草稿(draft)或未支付的发票没有这个字段,所以要在代码里做判断,避免返回空链接。 - 测试验证:用Stripe测试模式生成测试订阅和发票,验证下载链接是否能正常打开PDF。
内容的提问来源于stack exchange,提问作者Christoph C.
相关产品推荐
相关产品推荐

