使用Stripe结账持续报错‘Missing required param: name’求助
Stripe结账报错"Missing required param: name"的解决方案
问题描述
按照学校课程步骤实现Stripe结账功能时,持续触发以下错误:
{"errors":[{"message":"Missing required param: name.","locations":[{"line":2,"column":3}],"path":["checkout"]}
已尝试完全复刻课程操作、查阅Stack Overflow相关问题、安装旧版本Stripe,均未解决问题。相关代码如下:
TypeDefs
const { gql } = require('apollo-server-express'); const typeDefs = gql` type Console { _id: ID name: String } type Product { _id: ID name: String description: String image: String quantity: Int price: Float console: Console } type Order { _id: ID purchaseDate: String products: [Product] } type User { _id: ID firstName: String lastName: String email: String orders: [Order] } type Checkout { session: ID } type Auth { token: ID user: User } type Query { consoles: [Console] products(console: ID, name: String): [Product] product(_id: ID!): Product user: User order(_id: ID!): Order checkout(products: [ID]!): Checkout } type Mutation { addUser(firstName: String!, lastName: String!, email: String!, password: String!): Auth addOrder(products: [ID]!): Order updateUser(firstName: String, lastName: String, email: String, password: String): User updateProduct(_id: ID!, quantity: Int!): Product login(email: String!, password: String!): Auth } `; module.exports = typeDefs;
Queries
import { gql } from "@apollo/client"; export const QUERY_PRODUCTS = gql` query getProducts($console: ID) { products(console: $console) { _id name description price quantity image console { _id } } } `; export const QUERY_ALL_PRODUCTS = gql` { products { _id name description price quantity console { name } } } `; export const QUERY_CONSOLES = gql` { consoles { _id name } } `; export const QUERY_USER = gql` { user { firstName lastName orders { _id purchaseDate products { _id name description price quantity image } } } } `; export const QUERY_CHECKOUT = gql` query getCheckout($products: [ID]!) { checkout(products: $products) { session } } `;
Resolvers
const { AuthenticationError } = require("apollo-server-express"); const { User, Product, Console, Order } = require("../models"); const { signToken } = require("../utils/auth"); const stripe = require("stripe")("sk_test_*********"); const resolvers = { Query: { consoles: async () => { return await Console.find(); }, products: async (parent, { console, name }) => { const params = {}; if (console) { params.console = console; } if (name) { params.name = { $regex: name }; } return await Product.find(params).populate("console"); }, product: async (parent, { _id }) => { return await Product.findById(_id).populate("console"); }, user: async (parent, args, context) => { if (context.user) { const user = await User.findById(context.user._id).populate({ path: "orders.products", populate: "console" }); user.orders.sort((a, b) => b.purchaseDate - a.purchaseDate); return user; } throw new AuthenticationError("Not logged in"); }, order: async (parent, { _id }, context) => { if (context.user) { const user = await User.findById(context.user._id).populate({ path: "orders.products", populate: "console" }); return user.orders.id(_id); } throw new AuthenticationError("Not logged in"); }, checkout: async (parent, args, context) => { const url = new URL(context.headers.referer).origin; const order = new Order({ products: args.products }); const { products } = await order.populate("products"); const line_items = []; for (let i = 0; i < products.length; i++) { // generate product id const product = await stripe.products.create({ name: products[i].name, description: products[i].description, images: [`${url}/images/${products[i].image}`] }); // generate price id using the product id const price = await stripe.prices.create({ product: product.id, unit_amount: products[i].price * 100, currency: "usd", }); // add price id to the line items array line_items.push({ price: price.id, quantity: 1 }); } const session = await stripe.checkout.sessions.create({ payment_method_types: ["card"], line_items, mode: "payment", success_url: `${url}/success?session_id={CHECKOUT_SESSION_ID}`, cancel_url: `${url}/` }); return { session: session.id }; } }, Mutation: { addUser: async (parent, args) => { const user = await User.create(args); const token = signToken(user); return { token, user }; }, addOrder: async (parent, { products }, context) => { console.log(context); if (context.user) { const order = new Order({ products }); await User.findByIdAndUpdate(context.user._id, { $push: { orders: order } }); return order; } throw new AuthenticationError("Not logged in"); }, updateUser: async (parent, args, context) => { if (context.user) { return await User.findByIdAndUpdate(context.user._id, args, { new: true }); } throw new AuthenticationError("Not logged in"); }, updateProduct: async (parent, { _id, quantity }) => { const decrement = Math.abs(quantity) * -1; return await Product.findByIdAndUpdate(_id, { $inc: { quantity: decrement } }, { new: true }); }, login: async (parent, { email, password }) => { const user = await User.findOne({ email }); if (!user) { throw new AuthenticationError("Incorrect credentials"); } const correctPw = await user.isCorrectPassword(password); if (!correctPw) { throw new AuthenticationError("Incorrect credentials"); } const token = signToken(user); return { token, user }; } } }; module.exports = resolvers;
排查分析
错误提示看似是GraphQL参数缺失,但实际问题出在Stripe API调用逻辑:
- 原代码每次结账都创建新的Stripe Product和Price,若数据库中某个Product的
name字段为空或未正确填充,products[i].name会返回undefined,导致创建Stripe Product时缺失必填的name参数; - 新版Stripe API对Checkout Session的
line_items结构有更严格的校验,单独创建Product的流程容易出现参数传递遗漏。
修复方案
1. 检查数据库数据
确认MongoDB中所有Product文档的name字段都已正确赋值,无空值或未定义情况。
2. 修改CheckoutResolver逻辑
无需单独创建Stripe Product和Price,直接在line_items中通过price_data定义产品信息,既简化流程又避免参数缺失问题:
checkout: async (parent, args, context) => { const url = new URL(context.headers.referer).origin; const order = new Order({ products: args.products }); const { products } = await order.populate("products"); const line_items = []; for (let i = 0; i < products.length; i++) { // 提前校验产品名称,避免空值传入Stripe if (!products[i].name) { throw new Error(`产品ID ${products[i]._id} 未设置名称`); } line_items.push({ price_data: { currency: "usd", product_data: { name: products[i].name, description: products[i].description, images: [`${url}/images/${products[i].image}`] }, unit_amount: Math.round(products[i].price * 100), // 确保是整数金额 }, quantity: 1 }); } const session = await stripe.checkout.sessions.create({ payment_method_types: ["card"], line_items, mode: "payment", success_url: `${url}/success?session_id={CHECKOUT_SESSION_ID}`, cancel_url: `${url}/` }); return { session: session.id }; }
3. 固定Stripe版本
在package.json中指定兼容的Stripe版本,避免版本自动升级导致的API变更问题:
"dependencies": { "stripe": "^10.17.0" }
验证说明
修改后重新启动服务,测试结账流程:
- 若数据库中存在无名称的产品,会提前抛出错误,方便快速定位数据问题;
- 正常产品会直接生成包含完整信息的Stripe Checkout Session,不会再触发"Missing required param: name"错误。
内容的提问来源于stack exchange,提问作者damarts
相关产品推荐
相关产品推荐

