通过Stripe客户ID查询订阅ID返回undefined,无法取消订阅求助
修复通过Stripe客户ID取消订阅的问题
问题根源
- 默认不返回关联订阅数据:
stripe.customers.retrieve默认仅返回客户基础信息,不会自动拉取关联的订阅列表,导致customer.subscriptions为空或undefined。 - 订阅ID提取错误:就算拿到订阅列表,
customer.subscriptions.data[0]是整个订阅对象,并非订阅ID,需要提取其id属性。 - 未等待异步操作完成:
stripe.subscriptions.del是异步方法,不加await会导致数据库先更新,订阅却可能还没取消成功。 - 缺少边界判断:未检查用户是否存在有效订阅,直接取数组第一个元素会触发报错。
修复后的代码
module.exports.cancelSubscription = async (req, res) => { try { const user = await User.findById(req.user.id); if (!user) { req.flash('error', '找不到该用户'); return res.redirect('/users'); } // 调用retrieve时指定expand参数,展开关联的订阅数据 const customer = await stripe.customers.retrieve(user.stripeId, { expand: ['subscriptions'] }); // 检查是否存在有效订阅 if (!customer.subscriptions || customer.subscriptions.data.length === 0) { req.flash('error', '该用户没有有效的订阅'); return res.redirect(`/users/${user._id}`); } // 提取第一个订阅的ID const subscriptionId = customer.subscriptions.data[0].id; // 等待订阅取消操作完成 await stripe.subscriptions.del(subscriptionId, { at_period_end: false }); // 更新数据库中的订阅状态 user.subscription.active = "cancelled"; await user.save(); req.flash('success', '订阅已取消'); res.redirect(`/users/${user._id}`); } catch (err) { // 捕获API或数据库操作错误 req.flash('error', `取消订阅失败:${err.message}`); res.redirect(`/users/${user._id}`); } };
关键修改说明
- 添加expand参数:在
stripe.customers.retrieve中传入{ expand: ['subscriptions'] },让Stripe返回客户关联的订阅数据。 - 正确提取订阅ID:从订阅对象中获取
id属性,而非直接使用整个对象。 - 等待异步操作:给
stripe.subscriptions.del加上await,确保订阅取消完成后再更新数据库。 - 增加错误处理:用try/catch包裹逻辑,处理API调用、数据库操作的异常,同时判断订阅是否存在,避免空数组报错。
- 优化提示信息:针对不同场景返回对应提示,提升用户体验。
内容的提问来源于stack exchange,提问作者econobro
相关产品推荐
相关产品推荐

