node.js - 使用 Stripe Firebase 扩展 Webhook 未触发运行订阅付款

标签 node.js google-cloud-firestore stripe-payments webhooks firebase-extensions

我将 the Stripe Subscriptions extension 添加到我的 Firebase/Vue 应用程序中,以便我可以为我的客户管理订阅计划,但是我遇到了我认为是 Stripe webhook 的问题。
我通过像教程中所说的那样设置 firebase.rules 来开始扩展安装:
firebase.rules:

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /{document=**} {
      allow read, write;
    }
    match /customers/{uid} {
      allow read, write: if request.auth.uid == uid;

      match /checkout_sessions/{id} {
        allow read, write: if request.auth.uid == uid;
      }
      match /subscriptions/{id} {
        allow read, write: if request.auth.uid == uid;
      }
    }

    match /products/{id} {
      allow read: if true;
      allow write: if false;

      match /prices/{id} {
        allow read: if true;
        allow write: if false;
      }
    }
  }
}
我像下面这样配置了 Stripe webhook,并在 firebase 扩展中添加了 webhook secret :
enter image description here
我还在 Stripe 仪表板中创建了一个受限 key ,并将其添加到扩展中。
当我测试从 Stripe 仪表板创建新产品时,webhook 成功并在 firebase 中创建了一个集合:
条纹产品仪表板:
enter image description here
消防店:
enter image description here
现在,问题是:
当我尝试创建并完成 Stripe 结帐时出现问题。从教程中,看起来我需要调用 stripe.redirectToCheckout() 并且它会为我处理大部分内容,但我似乎无法找到结帐 session 的 sessionId。这是他们展示的示例:
const docRef = await db
  .collection('customers')
  .doc(currentUser.uid)
  .collection('checkout_sessions')
  .add({
    price: 'price_1GqIC8HYgolSBA35zoTTN2Zl',
    success_url: window.location.origin,
    cancel_url: window.location.origin,
  });
// Wait for the CheckoutSession to get attached by the extension
docRef.onSnapshot((snap) => {
  const { sessionId } = snap.data();
  if (sessionId) {
    // We have a session, let's redirect to Checkout
    // Init Stripe
    const stripe = Stripe('pk_test_1234');
    stripe.redirectToCheckout({ sessionId });
  }
});
这是我的实现:
 async checkoutv2(item) {
      let currentUser = this.getCurrentUser();
      const stripe = window.Stripe(this.publishableKey);

      const docRef = await db
        .firestore()
        .collection("customers")
        .doc(currentUser.uid)
        .collection("checkout_sessions")
        .add({
          unit_amount: item["unit_amount"],
          plan: item["id"],
          description: item["description"],
          interval: item["interval"],
          currency: item["currency"],
          type: item["type"],
          interval_count: item["interval_count"],
          active: item["active"],
          // allow_promotion_codes: true,
          // tax_rates: ["txr_1HCshzHYgolSBA35WkPjzOOi"],
          success_url: window.location.origin,
          cancel_url: window.location.origin,
          mode: "subscription",
          metadata: {},
        });

      // Wait for the CheckoutSession to get attached by the extension
      docRef.onSnapshot((snap) => {
        const { sessionId } = snap.data();
        if (sessionId) {
          // We have a session, let's redirect to Checkout
          // Init Stripe
          stripe.redirectToCheckout({ sessionId });
        } else {
          console.log("NOPE");
        }
      });
    },
在将 CheckOutSession 添加到 Firestore 之后,它似乎“附加”到扩展,并且创建了 session ID 并将其添加到文档中。但我认为我的版本不会发生这种情况。正在创建 checkout_sessions ,但没​​有 sessionId
enter image description here
这是 snap 数据的样子:
enter image description heresessionId 上没有任何内容,但它确实有自己的 id,我相信这是 Firestore 自动为集合创建的 id。
查看我的日志,没有触发任何 webhook。当我测试特定的 webhook 事件时,有些会成功,有些则不会。
成功:
  • 与价格、产品创建/更新/删除有关的任何事情。
  • checkout.session.completed
  • customer.subscription.created

  • 失败(错误状态代码 400):
  • customer.subscription.updated
  • customer.subscription.deleted(日志:[customer.subscription.deleted] 类型的 Stripe 事件 [evt_000000000000000] 的 Webhook 处理程序失败:没有这样的订阅:'sub_00000000000000')

  • 谁能告诉这是怎么回事?我正在使用 Stripe API 版本:2017-06-05。我已将以下内容添加到我的 index.html 中:
      <!-- Firebase App (the core Firebase SDK) is always required and must be listed first -->
        <script src="https://www.gstatic.com/firebasejs/7.14.6/firebase.js"></script>
        <script src="https://www.gstatic.com/firebasejs/7.14.6/firebase-functions.js"></script>
    
        <!-- If you enabled Analytics in your project, add the Firebase SDK for Analytics -->
        <script src="https://www.gstatic.com/firebasejs/7.14.5/firebase-analytics.js"></script>
    
        <!-- Add Firebase products that you want to use -->
        <script src="https://www.gstatic.com/firebasejs/7.14.5/firebase-auth.js"></script>
        <script src="https://www.gstatic.com/firebasejs/7.14.5/firebase-firestore.js"></script>
    
        <script src="https://cdn.firebase.com/libs/firebaseui/3.5.2/firebaseui.js"></script>
        <link
          type="text/css"
          rel="stylesheet"
          href="https://cdn.firebase.com/libs/firebaseui/3.5.2/firebaseui.css"
        />
    
    我的 package.json:
    {
      "name": "mathpath",
      "version": "0.1.0",
      "private": true,
      "description": "## Project setup ``` npm install ```",
      "author": "",
      "scripts": {
        "serve": "vue-cli-service serve",
        "build": "vue-cli-service build",
        "lint": "vue-cli-service lint",
        "start": "node index.js",
        "bd": "vue-cli-service build && firebase deploy"
      },
      "main": "babel.config.js",
      "dependencies": {
        "aws-sdk": "^2.719.0",
        "axios": "^0.19.2",
        "bootstrap": "^4.5.0",
        "bootstrap-vue": "^2.1.0",
        "core-js": "^3.6.5",
        "dns": "^0.2.2",
        "express": "^4.17.1",
        "firebase": "^7.17.1",
        "firebase-admin": "^9.0.0",
        "firebaseui": "^4.6.0",
        "fs": "0.0.1-security",
        "jquery": "^3.5.1",
        "katex": "^0.12.0",
        "markdown-it": "^11.0.0",
        "markdown-it-katex": "^2.0.3",
        "mathjax-node": "^2.1.1",
        "pg": "^8.2.2",
        "pg-hstore": "^2.3.3",
        "sequelize": "^6.3.0",
        "showdown": "^1.9.1",
        "showdown-katex": "^0.8.0",
        "slugify": "^1.4.5",
        "stripe": "^8.83.0",
        "uniqid": "^5.2.0",
        "vue": "^2.6.11",
        "vue-katex": "^0.4.0",
        "vue-router": "^3.3.4",
        "vue-stripe-checkout": "^3.5.7",
        "vue-youtube-embed": "^2.2.2",
        "vuefire": "^2.2.3",
        "vuex": "^3.5.1"
      },
      "devDependencies": {
        "@babel/polyfill": "^7.7.0",
        "@vue/cli-plugin-babel": "~4.4.0",
        "@vue/cli-plugin-eslint": "~4.4.0",
        "@vue/cli-service": "~4.4.0",
        "babel-eslint": "^10.1.0",
        "bootstrap": "^4.3.1",
        "eslint": "^6.7.2",
        "eslint-plugin-vue": "^6.2.2",
        "mutationobserver-shim": "^0.3.3",
        "popper.js": "^1.16.0",
        "portal-vue": "^2.1.6",
        "sass": "^1.19.0",
        "sass-loader": "^8.0.0",
        "vue-cli-plugin-bootstrap-vue": "~0.6.0",
        "vue-template-compiler": "^2.6.11"
      },
      "eslintConfig": {
        "root": true,
        "env": {
          "node": true
        },
        "extends": [
          "plugin:vue/essential",
          "eslint:recommended"
        ],
        "parserOptions": {
          "parser": "babel-eslint"
        },
        "rules": {
          "no-console": "off",
          "no-restricted-syntax": [
            "error",
            {
              "selector": "CallExpression[callee.object.name='console'][callee.property.name!=/^(log|warn|error|info|trace)$/]",
              "message": "Unexpected property on console object was called"
            }
          ]
        }
      },
      "browserslist": [
        "> 1%",
        "last 2 versions",
        "not dead"
      ],
      "license": "ISC"
    }
    
    

    最佳答案

    我遇到了同样的问题。
    这是我在开始工作之前更改的一些内容,我不确定究竟是什么修复了它:

  • 关闭我的 firebase 模拟器并测试生产数据。它似乎在修复之前在模拟器中工作(除了原始帖子中提到的问题),但我还没有测试它是否在模拟器后修复中工作。
  • 删除了我在 Stripe 中的所有测试数据和 webhook 并重新开始。
  • 更新了我所有的 firebase 和 vue-stripe-checkout 依赖项:

  • "firebase": "7.19.1",
    "firebase-admin": "^9.1.1",
    "firebase-functions": "^3.11.0",
    "firebase-tools": "^8.10.0",
    "firebaseui": "^4.6.1",
    "vue-stripe-checkout": "^3.5.7"
  • 从 2020-03-20 到 2020-08-27 更新了 Stripe 仪表板中的 Stripe API。
  • 删除了扩展并使用 CLI 而不是控制台重新安装。配置扩展时我唯一改变的是将客户集合设置为“用户”,因为这是我的应用程序中的约定:https://firebase.google.com/products/extensions/firestore-stripe-subscriptions

  • 完成所有这些之后,我在 Stripe 中创建了一个测试订阅产品,并看到它出现在我的产品系列中。这在修复之前已经有效。新的是我现在看到 sessionId 作为第二个 snap.data() 响应的一部分。第一个响应看起来就像“修复”之前的那个,我以为它又失败了,但是等待一两秒钟后,出现了一个带有附加 sessionId 参数的新响应👀
    我也在用 Vue。然后我进行该 session 并将其提交以更新状态。我观察这个 session 的变化,然后调用 checkoutRef 函数。这一次,用户的集合将使用新订阅进行更新。
    对我来说,这段代码在 store-auth.js
    async checkoutUser({ commit }, payload) {
        let userId = firebaseAuth.currentUser.uid;
    
        const docRef = await firebaseDb
          .collection("users")
          .doc(userId)
          .collection("checkout_sessions")
          .add({
            price: "YOUR_PRICE_ID",
            success_url: window.location.origin,
            cancel_url: window.location.origin,
            mode: "subscription"
          });
    
        docRef.onSnapshot(snap => {
          const test = snap.data();
    
          const { sessionId } = snap.data();
          if (sessionId) {
            commit("setSession", sessionId);
          }
        });
      },
    
    无论你在哪里使用 vue-stripe-checkout。对我来说,它在 PagePlans.vue 上
        <stripe-checkout
        ref="checkoutRef"
        :pk="publishableKey"
        :mode="mode"
        :items="items"
        :successUrl="successUrl"
        :cancelUrl="cancelUrl"
        :session-id="sessionId"
    
      watch: {
        currentSession: {
          handler(newValue, oldValue) {
            this.sessionId = newValue
    
            this.$refs.checkoutRef.redirectToCheckout({scenarioId: newValue.sessionId})
          }
        }
      },
      computed: {
        ...mapGetters("auth", ["currentSession"]),
      },
      methods: {
        ...mapActions("auth", [
          "checkoutUser",
        ]),
        async checkout() {
          await this.checkoutUser()
        }
      }
    
    

    关于node.js - 使用 Stripe Firebase 扩展 Webhook 未触发运行订阅付款,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63363098/

    相关文章:

    firebase - 是否可以向 Firebase Firestore 规则添加评论?

    Firebase Firestore : Is there a way to enforce required fields for all documents in a collection?

    javascript - 如何用 React Native 实现 Stripe?

    ruby-on-rails - 使用 Stripe::Card 创建一个新的 Stripe::Charge

    node.js - 将 MeteorJs 应用程序部署到 Google App Engine

    node.js - 安全 Node 、js API 路由

    javascript - Node .js `request.get` : store body in variable

    node.js - 在发送 POST 之前与远程服务器协商最大请求体大小

    firebase - 如何在 Vue.js 中获取新创建的 Firestore 文档的 ID?

    javascript - 将银行帐户数据添加到 strip 而​​不保存到 API 或数据库表