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

Netlify集成Stripe Checkout报错“Bad request, missing form”求助

问题描述

我正尝试将Stripe Checkout集成到已上线的Netlify网站中,但代码的服务端与客户端均未正常运行,返回“Bad request, missing form”响应,似乎无法接收POST请求。我已配置netlify.toml和_redirect文件,本地环境可正常运行,但部署后功能失效,该如何解决?

相关代码

checkout.js

const button = document.getElementById("checkout-button")
button.addEventListener("click", () => {
  fetch('/create-checkout-session', {
    method: 'POST',
    headers: {
      "Content-Type": "application/json"
    },
     body: JSON.stringify({
      //  items: [{ id: "Black Sweatsuit"},
      //          { id: "Grey Sweatsuit"},
      //          { id: "Red Sweatsuit"},
      //          { id: "Blue Sweatsuit"},
      //          { id: "Black T-Shirt"},
      //          { id: "Blue T-Shirt"},
      //          { id: "Purple T-Shirt"}
      //  ],
     }),
  })
    .then(res => {
    if (res.ok) return res.json()
    return res.json().then(json => Promise.reject(json))
  })
    .then(({ url }) => {
    window.location = url
  })
    .catch(e => {
      console.error(e.error)
  })
})

server.js

const stripe = require('stripe')('sk_live_XXXXXXX')

const express = require('express')
const app = express()
app.use(express.static('public'))
app.use(express.json())

const YOUR_DOMAIN = 'http://www.kimiee-kreates.com';

const storeItems = new Map([
   [1, { priceId: 'price_XXXX', name: "El Chapo"}],
   [2, { priceId: 'price_XXXX', name: "Joker"}],
   [3, { priceId: 'price_XXXX', name: "Joker"}],
   [4, { priceId: 'price_XXXX', name: "She Hit Different"}],
   [5, { priceId: 'price_XXXX', name: "Icy Girl"}],
   [6, { priceId: 'price_XXXX', name: "Girls don't Cry"}],
   [7, { priceId: 'price_XXXX', name: "Black Kaws"}],
   [8, { priceId: 'price_XXXX', name: "Orange Kaws"}],
   [9, { priceId: 'price_XXXX', name: "Scarface Monoly"}],
   [10, { priceId: 'price_XXXX',name: "Run, Rick & Morty"}],
   [11, { priceId: 'price_XXXX', name: "Glo Sun"}],
   [12, { priceId: 'price_XXXX', name: "Child's Play"}],
   [13, { priceId: 'price_XXXX', name: "Scream"}],
   [14, { priceId: 'price_XXXX', name: "Vegeta - Blue & Black"}],
   [15, { priceId: 'price_XXXX', name: "Goku"}],
   [16, { priceId: 'price_XXXX', name: "Juice"}],
   [17, { priceId: 'price_XXXX', name: "Rick & Morty"}],
   [18, { priceId: 'price_XXXX', name: "Vegeta"}],
])

app.post('/create-checkout-session', async (req, res) => {
    const session = await stripe.checkout.sessions.create({
        line_items: [
          { 
            price:'price_1M334EJGTDSvYp0wR4rUafhO',
            quantity: 1,
            adjustable_quantity: {
              enabled: true,
            }
          },
          { 
            price:'price_1M334MJGTDSvYp0wRqy65q46',
            quantity: 1,
            adjustable_quantity: {
              enabled: true,
            }
          },
        ],
        payment_method_types: ['card'],
          mode: 'payment',
          success_url: `${YOUR_DOMAIN}/success.html`,
          cancel_url: `${YOUR_DOMAIN}/cancel.html`,
          automatic_tax: {enabled: true},
      });
    
      res.redirect(303, session.url);
    });
解决方案

1. 改用Netlify Functions部署后端逻辑

Netlify不支持直接运行常规Express服务器,必须将后端接口改成Netlify无服务器函数:

  • 在项目根目录创建netlify/functions文件夹
  • 将server.js中的结账逻辑提取为单独函数文件netlify/functions/create-checkout-session.js:
const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY); // 用环境变量存密钥,禁止硬编码

exports.handler = async (event) => {
  // 仅处理POST请求
  if (event.httpMethod !== 'POST') {
    return {
      statusCode: 405,
      body: JSON.stringify({ error: 'Method not allowed' })
    };
  }

  try {
    const session = await stripe.checkout.sessions.create({
      line_items: [
        { 
          price:'price_1M334EJGTDSvYp0wR4rUafhO',
          quantity: 1,
          adjustable_quantity: { enabled: true }
        },
        { 
          price:'price_1M334MJGTDSvYp0wRqy65q46',
          quantity: 1,
          adjustable_quantity: { enabled: true }
        },
      ],
      payment_method_types: ['card'],
      mode: 'payment',
      success_url: `${process.env.YOUR_DOMAIN}/success.html`,
      cancel_url: `${process.env.YOUR_DOMAIN}/cancel.html`,
      automatic_tax: { enabled: true },
    });

    return {
      statusCode: 303,
      headers: {
        Location: session.url
      },
      body: ''
    };
  } catch (error) {
    return {
      statusCode: 500,
      body: JSON.stringify({ error: error.message })
    };
  }
};

2. 修改客户端请求路径

Netlify Functions的访问路径格式为/.netlify/functions/[函数名],更新checkout.js中的fetch地址:

fetch('/.netlify/functions/create-checkout-session', {
  // 其余代码保持不变
})

3. 配置Netlify环境变量

在Netlify后台的「项目设置 → 环境变量」中添加:

  • STRIPE_SECRET_KEY:你的Stripe生产秘钥(sk_live_xxx)
  • YOUR_DOMAIN:网站的HTTPS域名(Netlify部署的站点默认启用HTTPS,不要用HTTP)

4. 修复客户端响应处理逻辑

服务端返回303重定向,客户端原来的JSON解析逻辑会报错,调整为:

.then(res => {
  if (res.redirected) {
    window.location = res.url;
    return;
  }
  if (res.ok) return res.json();
  return res.json().then(json => Promise.reject(json));
})
// 删除原来的.then(({url}) => window.location = url)

5. 检查Netlify配置文件

确保netlify.toml配置正确,无需额外重定向规则(Netlify会自动处理Functions路径):

[build]
  command = "npm run build" # 替换为你的项目构建命令
  publish = "public" # 你的静态文件目录

[[redirects]]
  from = "/*"
  to = "/index.html"
  status = 200

6. 排查"Bad request, missing form"错误

  • 用Netlify后台的「Functions → 日志」查看请求详情,确认请求是否到达函数、请求体格式是否正确
  • 确保客户端请求的Content-Type为application/json(当前代码已设置)
  • 不要在代码中硬编码敏感信息,必须用环境变量

内容的提问来源于stack exchange,提问作者user16147870

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 09:05:22