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

Node.js报错Cannot read property 'reduce' of undefined的SwiftUI支付问题

Stripe支付对接报错修复:Cannot read property 'reduce' of undefined

问题背景

在Glitch部署基于Express的Node.js服务器,集成Stripe与CORS用于对接SwiftUI电商APP支付功能时,控制台出现以下错误:

(node:1314) UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'reduce' of undefined
at calculateOrderAmount (/app/server.js:11:23)

错误来自计算订单总金额的calculateOrderAmount函数。

错误原因

  1. 前后端数据格式不匹配:前端直接将商品数组作为请求体发送,但后端期望接收包含items字段的对象,导致后端req.body.items为undefined,调用reduce时崩溃。
  2. reduce缺少初始值:即使items是有效数组,当数组为空时,无初始值的reduce也会抛出错误。
  3. 额外问题:服务器代码误用Stripe公钥(应使用Secret Key),且未配置CORS中间件(跨域请求会失败)。

修复方案

1. 前端修改(SwiftUI)

修改startCheckout函数,将请求体包装为包含items键的对象:

extension OrderView {
    private func startCheckout(completion: @escaping (String?) -> Void) {
        let url = URL(string: "https://rogue-quartz-ounce.glitch.me/create-payment-intent")!
        var request = URLRequest(url: url)
        request.httpMethod = "POST"
        request.setValue("application/json", forHTTPHeaderField: "Content-Type")
        
        // 修复:将商品数组包装为带items键的字典
        let requestBody = ["items": order.products]
        do {
            request.httpBody = try JSONEncoder().encode(requestBody)
        } catch {
            print("编码失败:\(error)")
            completion(nil)
            return
        }

        URLSession.shared.dataTask(with: request) { data, response, error in
            guard let data = data, error == nil,
                  (response as? HTTPURLResponse)?.statusCode == 200
            else {
                completion(nil)
                print(error?.localizedDescription ?? "请求失败")
                return
            }

            let checkoutIntentResponse = try? JSONDecoder().decode(CheckoutIntentResponse.self, from: data)
            completion(checkoutIntentResponse?.clientSecret)
        }.resume()
    }
}

2. 后端修改(Node.js/Express)

  • 添加CORS中间件
  • 替换Stripe密钥为Secret Key
  • 给reduce添加初始值0
  • 添加参数校验,避免items为undefined或非数组时崩溃
const express = require("express");
const app = express();
// 修复:使用Stripe Secret Key(注意保密,不要公开)
const stripe = require("stripe")("your_stripe_secret_key");
// 添加CORS中间件
const cors = require("cors");

app.use(express.static("public"));
app.use(express.json());
app.use(cors()); // 启用CORS处理跨域请求

const calculateOrderAmount = (items) => {
    // 修复1:校验items是否为数组,非数组则返回0
    if (!Array.isArray(items)) return 0;
    // 修复2:给reduce添加初始值0,避免空数组报错
    const total = items.reduce((previous, current) => {
        // 额外:校验current是否有price属性,避免意外错误
        return previous + (current.price || 0);
    }, 0);
    return total * 100;
};

app.post("/create-payment-intent", async (req, res) => {
    const { items } = req.body;

    try {
        const paymentIntent = await stripe.paymentIntents.create({
            amount: calculateOrderAmount(items),
            currency: "gbp",
            automatic_payment_methods: {
                enabled: true,
            },
        });

        res.send({
            clientSecret: paymentIntent.client_secret,
        });
    } catch (error) {
        // 修复:添加错误捕获,避免未处理的Promise拒绝
        res.status(500).send({ error: error.message });
    }
});

app.listen(8080, () => console.log("Node server listening on port 8080!"));

额外注意事项

  • Stripe密钥区分Publishable Key(前端用)和Secret Key(后端用),务必不要混淆或公开Secret Key。
  • 前端避免使用try!强制解包,改用do-catch处理编码错误,防止APP崩溃。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 02:05:59