Node.js 集成错误条带无效值应为客户端机密字符串。您指定了:未定义
我有一个react项目,其中包含nodejs服务器端代码,并实现了stripe。我在本地机器上用测试卡测试了条带代码,效果很好,但当我将其上传到firebase主机并尝试在那里进行测试时,我收到了如下错误“Uncaught(in promise)IntegrationError:stripe的值无效。confirmCardPayment intent secret:值应为客户端密码字符串。您指定了“未定义”。所以我认为nodejs不能上传到firebase,所以我做了云计算,但仍然得到了相同的错误。我认为这是因为我是如何用URL中的项目位置、项目id和函数名调用API的其余部分的。这是我的服务器端代码Node.js 集成错误条带无效值应为客户端机密字符串。您指定了:未定义,node.js,reactjs,firebase,stripe-payments,Node.js,Reactjs,Firebase,Stripe Payments,我有一个react项目,其中包含nodejs服务器端代码,并实现了stripe。我在本地机器上用测试卡测试了条带代码,效果很好,但当我将其上传到firebase主机并尝试在那里进行测试时,我收到了如下错误“Uncaught(in promise)IntegrationError:stripe的值无效。confirmCardPayment intent secret:值应为客户端密码字符串。您指定了“未定义”。所以我认为nodejs不能上传到firebase,所以我做了云计算,但仍然得到了相同的错
const express = require("express");
const app = express();
const cors = require("cors");
const bodyParser = require("body-parser")
const functions = require("firebase-functions");
const admin = require("firebase-admin");
admin.initializeApp();
const stripe = require("stripe")(functions.config().stripe.secret);
app.use(bodyParser.urlencoded({ extended: false }));
// parse application/json
app.use(bodyParser.json());
app.use(cors());
app.post("/", cors(), async (req, res) => {
try {
const { email, amount } = req.body;
const paymentIntent = await stripe.paymentIntents.create({
amount,
currency: "usd",
// Verify your integration in this guide by including this parameter
metadata: { integration_check: "accept_a_payment" },
receipt_email: email,
});
console.log(paymentIntent);
// return res.status(200).json({
// confirm: "abc123"
// })
res.status(200).send({ client_secret: paymentIntent["client_secret"] });
} catch (error) {
console.log(error);
}
});
exports.pay = functions.https.onRequest(app);
// Create and Deploy Your First Cloud Functions
// https://firebase.google.com/docs/functions/write-firebase-functions
exports.helloWorld = functions.https.onRequest((request, response) => {
response.send("hello from jerry")
console.log("Hello From Jerry");
});
// On sign up.
exports.processSignUp = functions.auth.user().onCreate((user) => {
// Check if user meets role criteria.
if (user.email) {
const customClaims = {
active: true,
accessLevel:"paid",
};
// Set custom user claims on this newly created user.
return admin
.auth()
.setCustomUserClaims(user.uid, customClaims)
.then(() => {
// Update real-time database to notify client to force refresh.
const metadataRef = admin.database().ref(user.uid);
// Set the refresh time to the current UTC timestamp.
// This will be captured on the client to force a token refresh.
return metadataRef.set({ refreshTime: new Date().getTime() });
})
.catch((error) => {
console.log(error);
});
}
});
这是我的代码
import React, { useState, useEffect } from "react";
import axios from "axios";
// MUI Components
import Card from "@material-ui/core/Card";
import CardContent from "@material-ui/core/CardContent";
import TextField from "@material-ui/core/TextField";
import access from "../../assets/icon-5.png";
import { useAuth } from "../../context/AuthContext";
import rocket from "../../assets/rocket.png";
import question from "../../assets/question-mark.png";
import { useHistory } from "react-router-dom";
import { connect } from "react-redux";
import { getProducts } from "../../actions/products";
import Spinner from "../Spinner/Spinner";
import moment from "moment";
import { setAlert } from "../../actions/alert";
import { useStripe, useElements, CardElement } from "@stripe/react-stripe-js";
import { makeStyles } from "@material-ui/core/styles";
import CardInput from "./CardInput";
import "./common.css";
import { Fragment } from "react";
const useStyles = makeStyles({
root: {
// maxWidth: 500,
},
content: {
display: "flex",
flexDirection: "column",
alignContent: "flex-start",
},
div: {
display: "flex",
flexDirection: "row",
alignContent: "flex-start",
justifyContent: "space-between",
},
button: {
margin: "2em auto 1em",
},
});
const HomePage = ({ getProducts, products, location, setAlert }) => {
const history = useHistory();
const { state } = location;
console.log(state, "params");
const { signup } = useAuth();
const classes = useStyles();
// State
const [totalPlan, setPurchaseSummary] = useState({
total: "19.99",
planAccess: "",
start: "",
end: "",
});
const { total, planAccess, start, end } = totalPlan;
const [loading, setLoading] = useState(true);
const [planList, setPlan] = useState({
bronze: "",
silver: "",
gold: "",
platinum: "",
amount: 0,
});
const { bronze, silver, gold, platinum, amount } = planList;
const [formData, setFormData] = useState({
email: "",
password: "",
confirmPassword: "",
});
const { email, customer, password, confirmPassword } = formData;
const onChange = (e) =>
setFormData({
...formData,
[e.target.name]: e.target.value,
});
const stripe = useStripe();
const elements = useElements();
console.log(products, "products");
let productArray = Object.values(products);
let firstItemInProductArray = [];
firstItemInProductArray = productArray[0];
console.log(firstItemInProductArray);
let onProductsArray = Object.values(firstItemInProductArray);
console.log(onProductsArray);
let holderArray = [];
holderArray = holderArray.concat(onProductsArray);
let secondProductArray = [];
secondProductArray = holderArray[0];
console.log(secondProductArray);
const handleSubmit = async (e) => {
e.preventDefault();
if (!stripe || !elements) {
// Stripe.js has not yet loaded.
// Make sure to disable form submission until Stripe.js has loaded.
return null;
}
const res = await axios.post("http://us-central-nbe-online-prep.cloudfunctions.net/pay", {
email: email,
amount,
});
const clientSecret = res.data["client_secret"];
console.log(clientSecret);
const { paymentIntent } = await stripe.confirmCardPayment(
clientSecret,
{
payment_method: {
type: "card",
card: elements.getElement(CardElement),
billing_details: {
email: email,
},
},
}
);
let results = {
total,
planAccess,
start,
end,
customer,
};
try {
if (!!results && paymentIntent.status === "succeeded") {
await signup(email, password);
history.replace({
pathname: "/success",
state: { result: results },
});
}
} catch (error) {
setAlert(`${error.message}`, "danger");
}
};
useEffect(() => {
setLoading(false);
}, [setLoading]);
const selectProduct = (plan) => {
switch (plan) {
case "bronze":
console.log("bronze");
setPlan((prevState) => ({
...prevState,
bronze: "bronze",
silver: "",
gold: "",
platinum: "",
amount: 1999,
}));
setPurchaseSummary((prevState) => ({
...prevState,
total: "19.99",
planAccess: "Bronze",
start: moment().format("MMMM Do YYYY, h:mm:ss a"),
end: moment().add(30, "days").format("MMMM Do YYYY, h:mm:ss a"),
}));
break;
case "silver":
console.log("silver");
setPlan((prevState) => ({
...prevState,
bronze: "",
silver: "silver",
gold: "",
platinum: "",
amount: 3999,
}));
setPurchaseSummary((prevState) => ({
...prevState,
total: "39.99",
planAccess: "Silver",
start: moment().format(),
end: moment().add(1, "months"),
}));
break;
case "gold":
console.log("gold");
setPlan((prevState) => ({
...prevState,
bronze: "",
silver: "",
gold: "gold",
platinum: "",
amount: 6999,
}));
setPurchaseSummary((prevState) => ({
...prevState,
total: "69.99",
planAccess: "Gold",
start: moment().format(),
end: moment().add(3, "months"),
}));
break;
case "platinum":
console.log("platinum");
setPlan((prevState) => ({
...prevState,
bronze: "",
silver: "",
gold: "",
platinum: "platinum",
amount: 11999,
}));
setPurchaseSummary((prevState) => ({
...prevState,
total: "119.99",
planAccess: "Platinum",
start: moment().format(),
end: moment().add(12, "months"),
}));
break;
default:
break;
}
};
return (
<section className="container">
{!loading && stripe ? (
<Fragment>
<div className="grid-pay">
<div className="start">
<h1 style={{ color: "#000000", textAlign: "justify" }}>
Start Learning Today
</h1>
<p style={{ textAlign: "justify" }}>
It is a long established fact that a reader will be distracted
by the readable content of a page when looking at its layout.
The point of using Lorem Ipsum is that it has a more-or-less
normal distribution of letters, as opposed to using 'Content
here, content here', making it look like readable English.
</p>
<div style={{ marginTop: 20 }}>
<ul style={{ textAlign: "justify" }}>
<li style={{ color: "#000000" }}>
<div style={{ display: "flex" }}>
<div>
<img
alt="lock"
src={question}
style={{ width: 60, height: 60, marginBottom: 20 }}
/>
</div>
<div>
<p style={{ marginTop: 20, marginLeft: 10 }}>
Unlimited access to all courses
</p>
</div>
</div>
</li>
<li style={{ color: "#000000" }}>
{" "}
<div style={{ display: "flex" }}>
<div>
<img
alt="rocket icon"
src={rocket}
style={{ width: 60, height: 60, marginBottom: 20 }}
/>
</div>
<div>
<p style={{ marginTop: 20, marginLeft: 10 }}>
Hands-on exercises
</p>
</div>
</div>
</li>
<li style={{ color: "#000000" }}>
{" "}
<div style={{ display: "flex" }}>
<div>
<img
alt="lock"
src={access}
style={{ width: 60, height: 60, marginBottom: 20 }}
/>
</div>
<div style={{ marginTop: 20, marginLeft: 10 }}>
<p>Weekly additions and updates</p>
</div>
</div>
</li>
</ul>
</div>
</div>
<div>
<form onSubmit={(e) => handleSubmit(e)}>
<Card className={classes.root}>
<div>
<p
style={{
color: "#000000",
fontSize: 30,
textAlign: "justify",
marginLeft: 20,
marginTop: 20,
}}
>
Choose Your Plan
</p>
</div>
<div className="button-grid" style={{ display: "flex" }}>
<div
onClick={() => selectProduct("bronze")}
id={`${bronze}`}
className={`gray `}
style={{ paddingTop: 5 }}
>
<h3>$19.99</h3>
</div>
<div
onClick={() => selectProduct("silver")}
id={`${silver}`}
className={`gray `}
style={{ paddingTop: 5 }}
>
<h3>$39.99</h3>
</div>
<div
onClick={() => selectProduct("gold")}
id={`${gold}`}
className={`gray`}
style={{ paddingTop: 5 }}
>
<h3>$69.99</h3>
</div>
<div
onClick={() => selectProduct("platinum")}
id={`${platinum}`}
className={`gray`}
style={{ paddingTop: 5 }}
>
<h3>$119.99</h3>
</div>
</div>
<CardContent className={classes.content}>
<TextField
label="Name"
id="outlined-email-input"
helperText={`Enter full name`}
margin="normal"
variant="outlined"
type="text"
required
name="customer"
value={customer}
onChange={(e) => onChange(e)}
fullWidth
/>
<TextField
label="Email"
id="outlined-email-input"
helperText={`Email you'll recive updates and receipts on`}
margin="normal"
variant="outlined"
type="email"
required
name="email"
value={email}
onChange={(e) => onChange(e)}
fullWidth
/>
<TextField
label="Passwod"
id="outlined-password-input"
helperText={`Create Password for your account`}
margin="normal"
variant="outlined"
type="password"
required
name="password"
value={password}
onChange={(e) => onChange(e)}
fullWidth
/>
<TextField
label="confirm password"
id="outlined-password-input"
helperText={`Confirm Password`}
margin="normal"
variant="outlined"
type="password"
required
name="confirmPassword"
value={confirmPassword}
onChange={(e) => onChange(e)}
fullWidth
/>
<div
style={{
display: "flex",
justifyContent: "space-between",
}}
>
<div>
<h3>Amount</h3>
</div>
<div>
<p style={{ color: "#000", fontSize: 22 }}>${total}</p>
</div>
</div>
<div style={{ marginTop: 10 }}>
<CardInput />
</div>
</CardContent>
<div
style={{
marginTop: 50,
marginLeft: 10,
marginRight: 10,
marginBottom: 30,
}}
>
<input
style={{}}
type="submit"
className="btn-style-two btn-primary button-gradient"
value="Purchase"
/>
</div>
</Card>
</form>
</div>
</div>
</Fragment>
) : (
<Spinner />
)}
</section>
);
};
const mapStateToProps = (state) => ({
products: state.products,
});
export default connect(mapStateToProps, { getProducts, setAlert })(HomePage);
import React,{useState,useffect}来自“React”;
从“axios”导入axios;
//MUI组件
从“@物料界面/核心/卡片”导入卡片;
从“@material ui/core/CardContent”导入CardContent;
从“@material ui/core/TextField”导入TextField;
从“../../assets/icon-5.png”导入访问权限;
从“../../context/AuthContext”导入{useAuth}”;
从“../../assets/rocket.png”导入火箭;
从“../../assets/问号.png”导入问题;
从“react router dom”导入{useHistory};
从“react redux”导入{connect};
从“../../actions/products”导入{getProducts};
从“./Spinner/Spinner”导入微调器;
从“时刻”中导入时刻;
从“../../actions/alert”导入{setAlert};
从“@stripe/react stripe js”导入{useStripe,useElements,CardElement};
从“@material ui/core/styles”导入{makeStyles}”;
从“/CardInput”导入CardInput;
导入“/common.css”;
从“react”导入{Fragment};
const useStyles=makeStyles({
根目录:{
//最大宽度:500,
},
内容:{
显示:“flex”,
flexDirection:“列”,
alignContent:“灵活启动”,
},
分区:{
显示:“flex”,
flexDirection:“行”,
alignContent:“灵活启动”,
辩护内容:“间隔空间”,
},
按钮:{
页边空白:“2em自动1em”,
},
});
const主页=({getProducts,products,location,setAlert})=>{
const history=useHistory();
const{state}=位置;
console.log(状态为“params”);
const{signup}=useAuth();
const classes=useStyles();
//陈述
const[totalPlan,setPurchaseSummary]=useState({
总数:“19.99”,
计划访问:“,
开始:“,
完:,
});
const{total,planAccess,start,end}=totalPlan;
const[loading,setLoading]=useState(true);
常量[planList,setPlan]=useState({
青铜:“,
银币:“,
黄金:“,
白金:“,
金额:0,
});
常量{青铜、银、金、铂,数量}=平面图;
常量[formData,setFormData]=useState({
电邮:“,
密码:“”,
确认密码:“”,
});
const{email,customer,password,confirmPassword}=formData;
const onChange=(e)=>
setFormData({
…表格数据,
[e.target.name]:e.target.value,
});
常量stripe=useStripe();
常量元素=useElements();
控制台日志(产品,“产品”);
让productArray=Object.values(产品);
让firstItemInProductArray=[];
firstItemInProductArray=productArray[0];
log(firstItemInProductArray);
让onProductsArray=Object.values(firstItemInProductArray);
console.log(onProductsArray);
设holderArray=[];
holderArray=holderArray.concat(onProductsArray);
设secondProductArray=[];
secondProductArray=holderArray[0];
log(secondProductArray);
const handleSubmit=async(e)=>{
e、 预防默认值();
如果(!stripe | |!元素){
//Stripe.js尚未加载。
//确保在加载Stripe.js之前禁用表单提交。
返回null;
}
const res=等待axios.post(“http://us-central-nbe-online-prep.cloudfunctions.net/pay", {
电邮:电邮,,
数量
});
const clientSecret=res.data[“client_secret”];
console.log(clientSecret);
const{paymentIntent}=wait stripe.confirmCardPayment(
客户机密,
{
付款方式:{
输入:“卡片”,
卡片:elements.getElement(CardElement),
账单详情:{
电邮:电邮,,
},
},
}
);
让结果={
全部的
计划访问,
开始
完,,
顾客
};
试一试{
if(!!results&&paymentIntent.status==“successed”){
等待注册(电子邮件、密码);
历史。替换({
路径名:“/success”,
状态:{result:results},
});
}
}捕获(错误){
setAlert(`${error.message}`,`danger');
}
};
useffect(()=>{
设置加载(假);
},[setLoading]);
const selectProduct=(计划)=>{
道岔(平面图){
“青铜”案:
控制台日志(“青铜”);
setPlan((prevState)=>({
…国家,
青铜:“青铜”,
银币:“,
黄金:“,
白金:“,
金额:1999年,
}));
setPurchaseSummary((prevState)=>({
…国家,
总数:“19.99”,
planAccess:“青铜”,
开始:矩().format(“MMMM-Do-YYYY,h:mm:ss-a”),
结束:矩().添加(30,“天”).格式(“mm-Do-yyy,h:mm:ss-a”),
}));
打破
“银”案:
控制台日志(“银色”);
setPlan((prevState)=>({
…国家,
青铜:“,
银牌:“银牌”,
黄金:“,
白金:“,
金额:3999,
}));
setPurchaseSummary((prevState)=>({
…国家,
总数:“39.99”,
计划访问:“银色”,
开始:矩().format(),
结束:力矩()。添加(1,“月”),
}));
打破
案例“黄金”:
控制台日志(“黄金”);
setPlan((prevState)=>({
…国家,
铜牌:“