You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在自有网站实现Stripe发票用户下载功能?

获取Stripe订阅发票下载URL的技术方案

嘿,这个需求我之前做过好几次,其实Stripe已经给我们提供了很直接的解决办法,不用自己折腾生成PDF。下面分两种常用方案给你讲,你可以根据自己的场景选:

方案一:在Webhook接收时提前存储PDF URL(推荐)

既然你已经在用Webhook把发票数据存到数据库了,那最省心的方式就是在Webhook触发时直接把Stripe生成的发票PDF URL一起存下来,这样后面给用户展示账单时直接从数据库取就行,不用再额外调用Stripe API。

具体步骤:

  1. 在处理invoice.paid的Webhook事件时,从Stripe返回的invoice对象里拿到invoice_pdf字段,这就是该发票的直接下载URL。
  2. 把这个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.

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 03:59:11