长话短说 在本教程中,我们将探索如何将 Stripe 支付网关无缝集成到我们的全栈应用程序中,并轻松地将它们托管在 FL0 上。 🚀 介绍 无论是电子商务还是 SaaS 应用程序,支付网关都是我们项目的核心组成部分。 💳 在本指南中,我们将探讨如何简化这些集成,特别关注用于在线 Stripe Checkout。 支付处理的 Stripe 的开发人员友好的 API 可确保安全高效的交易,同时减少我们的开发时间。 例如,我们以 SaaS 应用程序支付页面为例。 我们将使用 作为后端,并使用 Postgres 作为数据库。在前端,我们使用 和 。 NodeJs ReactJs vite 后来我们会毫不费力地在 FL0 上托管我们的项目。 ⬆️ 那么,让我们从一点幽默开始吧: 概述 🧑💻 在本教程中,我们将创建一个简单的演示应用程序,用户可以在其中注册、选择计划并使用信用卡结账。 为此,我们需要创建 2 个独立的存储库,一个用于 ,另一个用于 。 backend frontend 文件夹结构 🗂️ 这是我们的两个文件夹结构的样子,仅供参考: 现在,让我们开始吧。 第 1 步:设置后端 为了提高效率,在本教程中,我们将利用“ ”模板。 fl0zone/blog-express-pg-sequelize 然后我们将删除对我们的项目不重要的任何文件或文件夹。 🧑💻 为了更全面地了解本教程,您可能需要参考 博客文章。 这篇 我们的模板封装了一个基本的 应用程序和一个 dockerized 数据库。 Node.js PostgreSQL 这是我们设置的相应 文件: docker-compose.yaml version: "3" services: app: build: context: . target: development env_file: .env volumes: - ./src:/usr/src/app/src ports: - 8081:80 depends_on: - db db: image: postgres:14 restart: always environment: POSTGRES_USER: admin POSTGRES_PASSWORD: admin POSTGRES_DB: my-startup-db volumes: - postgres-data:/var/lib/postgresql/data ports: - 5432:5432 volumes: postgres-data: 现在我们将继续安装一些必要的软件包📦 npm install bcrypt cookie-parser cors jsonwebtoken pg-hstore stripe 现在,我们需要获取 Stripe API 密钥🔑。为此,我们需要在 Stripe 上创建一个新帐户。 这里我们将使用 进行演示。 Test Mode 以下是该项目所需的环境变量列表。 .env.example STRIPE_PUBLISHABLE_KEY= STRIPE_SECRET_KEY= POSTGRES_DB_URI= secretKey= CLIENT_URL= 第 2 步:创建数据库模型 现在让我们开始设置数据库。 🐘 由于我们使用 Sequelize ORM,因此我们需要为用户数据创建一个模型。 这是我们模型的代码👇 models/userModel.js module.exports = (sequelize, DataTypes) => { const User = sequelize.define( "user", { email: { type: DataTypes.STRING, unique: true, isEmail: true, //checks for email format allowNull: false, }, password: { type: DataTypes.STRING, allowNull: false, }, tier: { type: DataTypes.STRING, allowNull: true, }, }, { timestamps: true } ); return User; }; 第 2 步:设置路线 现在,让我们继续创建我们的路线 - 帮助登录用户并存储会话 POST /login - 帮助创建新帐户 POST /signup - 生成并返回条带结账页面链接 POST /create-checkout-session 这3条路线被分成2个文件,如下: routes/userRoutes.js const express = require("express"); const userController = require("../controllers/userController"); const { signup, login } = userController; const userAuth = require("../middleware/userAuth"); const router = express.Router(); router.post("/signup", userAuth.saveUser, signup); router.post("/login", login); module.exports = router; routes/stripeRoute.js const express = require("express"); const { updatePlan } = require("../controllers/stripeController"); const router = express.Router(); router.post("/create-checkout-session", updatePlan); module.exports = router; 第 3 步:设置用户个人资料 🧑💻 为了设置用户个人资料,首先我们将定义一个中间件来检查新用户的电子邮件地址在注册过程中是否已存在于数据库中。 middleware/userAuth.js //importing modules const express = require("express"); const db = require("../models"); const User = db.users; const saveUser = async (req, res, next) => { console.log("here"); try { const checkEmail = await User.findOne({ where: { email: req.body.email, }, }); if (checkEmail) { return res.json(409).send("Authentication failed"); } next(); } catch (error) { console.log(error); } }; module.exports = { saveUser, }; 然后我们将继续定义我们的登录和注册功能👇 controllers/userController.js const bcrypt = require("bcrypt"); const db = require("../models"); const jwt = require("jsonwebtoken"); const User = db.users; const signup = async (req, res) => { try { const { email, password } = req.body; console.log(email); const data = { email, password: await bcrypt.hash(password, 10), }; //saving the user const user = await User.create(data); if (user) { let token = jwt.sign({ id: user.id }, process.env.secretKey, { expiresIn: 1 * 24 * 60 * 60 * 1000, }); res.cookie("jwt", token, { maxAge: 1 * 24 * 60 * 60, httpOnly: true }); console.log("user", JSON.stringify(user, null, 2)); console.log(token); return res.status(201).send(user); } else { return res.status(409).send("Details are not correct"); } } catch (error) { console.log(error); } }; // Login Authentication const login = async (req, res) => { try { const { email, password } = req.body; const user = await User.findOne({ where: { email: email, }, }); if (user) { const isSame = await bcrypt.compare(password, user.password); if (isSame) { let token = jwt.sign({ id: user.id }, process.env.secretKey, { expiresIn: 1 * 24 * 60 * 60 * 1000, }); res.cookie("jwt", token, { maxAge: 1 * 24 * 60 * 60, httpOnly: true }); //send user data return res.status(201).send(user); } else { return res.status(401).send("Authentication failed"); } } else { return res.status(401).send("Authentication failed"); } } catch (error) { console.log(error); } }; module.exports = { signup, login, }; 第 4 步:设置 Stripe Checkout 我们将在这里将 集成到我们的应用程序中。 Stripe Checkout 我们将使用 来管理付款并处理用户订阅。 Stripe API 以下代码创建一个新的 Stripe 结账会话。 💳 我们将向其提供付款方式类型、产品数据和数量。 我们还需要指定用户在成功付款或取消交易时将被重定向的 URL。 并且,如果一切正常,服务器将使用 Stripe 会话的 URL 进行响应。 ✅ controllers/stripeController.js const db = require("../models"); const Stripe = require("stripe"); const User = db.users; require("dotenv").config(); const stripe = Stripe(process.env.STRIPE_SECRET_KEY); const updatePlan = async (req, res) => { try { const { email, product } = req.body; const session = await stripe.checkout.sessions.create({ payment_method_types: ["card"], line_items: [ { price_data: { currency: "usd", product_data: { name: product.name, }, unit_amount: product.price * 100, }, quantity: product.quantity, }, ], mode: "payment", success_url: `${process.env.CLIENT_URL}/success`, cancel_url: `${process.env.CLIENT_URL}/`, }); //find a user by their email const user = await User.findOne({ where: { email: email, }, }); if (user) { await user.update({ tier: product.name }); return res.send({ url: session.url }); } else { return res.status(401).send("User not found"); } } catch (error) { console.log(error); } }; module.exports = { updatePlan, }; 最后,我们需要将所有路由添加到我们的入口点,即 server.js server.js const cors = require("cors"); const express = require("express"); require("dotenv").config(); const cookieParser = require("cookie-parser"); const db = require("./models"); const userRoutes = require("./routes/userRoutes"); const PORT = process.env.PORT || 8080; const stripeRoute = require("./routes/stripeRoute"); const app = express(); // Middlewares app.use(express.json()); app.use(express.urlencoded({ extended: true })); app.use(cookieParser()); app.use(cors()); // Routes app.use("/api/v1/users", userRoutes); app.use("/api/v1/stripe", stripeRoute); app.listen(PORT, () => { console.log("Server started at port 8080"); try { db.sequelize.sync({ force: true }).then(() => { console.log("db has been re sync"); }); } catch (error) {} }); 我们已经完成了后端 ✅ 现在让我们继续尝试将其部署到 上。 🔼 FL0 第 5 步:使用 FL0 进行部署 🚀 为了将我们的项目部署到 FL0,我们首先将 送到新的 GitHub 存储库。 我们的存储库推 这是我们存储库的链接以供参考: ://github.com/dalefl0/stripe-fl0-backend https 现在我们将前往 开始部署。 app.fl0.dev 这里我们需要创建一个新项目,例如将其命名为 。 stripe-fl0 现在我们需要创建一个新的 Postgres 实例。对于 Fl0,这需要不到 30 秒! ⏳ 设置完数据库后,我们需要继续在同一个项目中部署后端。 部署后端后,我们需要导入数据库连接字符串,如上所示☝️ 🙌 现在我们的后端已启动并正在运行。 UI 时间到了✨ 第 6 步:设置前端 为了设置前端,我们将从 开始。 ⚡️ template-react-vite 这包括我们启动和运行 项目所需的一切。 React-Vite 现在我们将继续安装一些软件包。 npm install @heroicons/react axios react-router-dom npm install postcss tailwindcss autoprefixer --save-dev 第 7 步:设置前端 为了快速构建我们的 UI 组件,我们将借助 的 以及 。 tailwind UI 定价部分组件 登录和注册组件 为了简洁起见,我们只看前端的重要功能。 完整的项目可以在以下位置找到: ://github.com/dalefl0/stripe-fl0-frontend https 现在,我们需要添加一个函数来处理条带结帐 src/components/PricingPlans.jsx ... const handleCheckout = (product) => { axios .post( `https://stripe-fl0-backend-dev.fl0.io/api/v1/stripe/create-checkout-session`, { email, product, } ) .then((res) => { if (res.data.url) { setTier(product.name); localStorage.setItem("tier", product.name); window.location.href = res.data.url; } }) .catch((err) => navigate("/cancel")); }; ... 该函数调用后端的 路由,接收链接,并将用户重定向到结账页面。 📄 /create-checkout-session 除此之外,我们还需要将 和 页面连接到相应的路由,并将用户数据存储在 中。 signup login localstorage 第 8 步:部署前端 对于前端,我们需要再次创建一个新的 ,并以类似的方式将其部署在同一个项目中。 存储库 然后,我们需要将 环境变量添加到前端部署,该变量应设置为后端的 URL。 VITE_APP_API_BASE_URL 我们还需要将后端的 环境变量设置为前端的托管 URL。 CLIENT_URL 完成后,我们的 FL0 项目将如下所示 👇 现在,让我们继续使用此实时演示链接尝试我们的应用程序: https://stripe-fl0-frontend-q8oo-dev.fl0.io/ 包起来 感谢您坚持到最后! 在本教程中,我们学习了如何通过将 轻松集成到我们的全栈应用程序中来构建支付页面。 🎉 Stripe Checkout 我们还使用 FL0 快速部署了我们的项目。 要开始构建您自己的具有支付功能的应用程序,请访问 fl0.com 🚀