【发布时间】:2020-09-26 17:45:05
【问题描述】:
我正在尝试将条带集成到我的应用程序中,事实证明它确实具有挑战性。
我的应用程序是 React 前端和用于数据库和托管的 google Firebase。
经过几天的文档和反复试验,我终于找到了这篇文章https://blog.risingstack.com/stripe-payments-integration-tutorial-javascript/
它非常全面且易于理解,因此我一直遵循这一点。 我的 react 应用程序的结构是有一个 index.js 文件,它是 dom 的根,然后是一个 app.js 文件,用于存储应用程序其余部分的导航。
我正在尝试添加能够获取客户信用卡详细信息并处理付款的商店页面或结帐页面。所以我决定使用条纹。
最初,我尝试使用 google firebase cloud 功能,但最终根本不起作用 - 旁注,我相信他们正在处理错误? - 然后我决定使用 express 和 axios 来处理 api 请求。
这似乎有效,除了来自条带的响应是“服务器响应状态为 405(不允许方法)”。
我认为这与我在本地运行此程序有关,因此请求作为 http 请求发送,但我经验不足,无法确定,我希望在部署此程序之前获得专家指导分期。当我在这里时,如何将 Cors 源更改为真实站点而不是本地主机?
代码如下,在此先感谢。 罗里
// File Location //
Olas/Server/index.js
// File Location //
const express = require('express');
const helmet = require('helmet');
const cors = require('cors');
const app = express();
const port = 3001;
const stripe = require('stripe')('****SECRET TEST KEY****');
app.use(cors({
origin: [/https:\/\/localhost:\d+$/],
allowedHeaders: ['Content-Type', 'Authorization'],
credentials: true
}));
app.post('/api/shop/order', async(req, res) => {
const order = req.body.order;
const source = req.body.source;
try {
const stripeOrder = await stripe.orders.create(order);
console.log('Order completed: ${stripeOrder.id}');
await stripe.orders.pay(stripeOrder.id, {source})
} catch (err) {
// Handle stripe errors here: No such coupon, sku, ect
console.log(`Order error: ${err}`);
return res.sendStatus(404);
}
return res.sendStatus(200);
});
app.get('/api/', (req, res) => res.send({ version: '1.0' }));
app.listen(port, () => console.log(`Example app listening on port ${port}!`));
// File Location //
src/Pages/Shop.js
// File Location //
import React, {Component} from "react";
import { CardElement } from 'react-stripe-elements';
import PropTypes from 'prop-types';
import axios from 'axios';
import qs from 'query-string-object';
import { injectStripe } from 'react-stripe-elements'
const prices = {
banana: 150,
cucumber: 100
};
const products = {
banana: "prod_HQJX0o5TAu8pJi",
cucumber: "prod_HQJYaYAlB1nSbJ",
};
const stripeAuthHeader = {
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': `Bearer *** TEST KEY`};
class Shop extends React.Component {
constructor(props) {
super(props);
this.state = {
fetching: false,
cart: {
banana: 0,
cucumber: 0
},
coupon: '',
email: '',
name: '',
address : {
line1: '',
city: '',
state: '',
country: '',
postal_code: ''
},
};
this.handleCartChange = this.handleCartChange.bind(this);
this.handleCartReset = this.handleCartReset.bind(this);
this.handleAddressChange = this.handleAddressChange.bind(this);
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleCartChange(evt) {
evt.preventDefault()
const cart = this.state.cart
cart[evt.target.name]+= parseInt(evt.target.value)
this.setState({cart})
}
handleCartReset(evt) {
evt.preventDefault()
this.setState({cart:{banana: 0, cucumber: 0}})
}
handleAddressChange(evt) {
evt.preventDefault()
const address = this.state.address
address[evt.target.name] = evt.target.value
this.setState({address})
}
handleChange(evt) {
evt.preventDefault()
this.setState({[evt.target.name]: evt.target.value})
}
handleSubmit(evt) {
evt.preventDefault();
this.setState({fetching:true});
const cart = this.state.cart;
this.props.stripe.createToken().then(({token}) => {
//Create Order
const order ={
currency: 'usd',
items: Object.keys(cart).filter((name) => cart[name] >0 ? true: false).map(
name => {
return {
type: 'good',
parent: products[name],
quantity: cart[name]
}
}),
email: this.state.email,
shipping: {
name: this.state.name,
address: this.state.address
}
}
// Add coupon if given
if (this.state.coupon) {
order.coupon = this.state.coupon
}
console.log(token);
//This is a simple direct charge from an earlier example//
// const price = cart.banana * prices.banana + cart.cucumber * prices.cucumber
// axios.post('https.//api.stripe.com/v1/charges',
// qs.stringify({
// source: token.id,
// amount: price,
// currency: 'usd'
// }),
// {headers:stripeAuthHeader})
// .then((resp) => {
// this.setState({fetching:false});
// alert('Thank you for your purchase! Your card has been charged with: ${(resp.data.amount / 100).toLocaleString(\'en-US\', {style: \'currency\', currency: \'usd\'})}`')
// })
// .catch(error => {
// this.setState({fetching: false});
// console.log(error)
// })
// .catch(error=> {
// this.setState({fetching:false});
// console.log(error)
// })
axios.post('http:localhost:3001/api/shop/order', {order, source: token.id})
.then(() => {
this.setState({fetching: false})
alert(`Thank you for your purchase!`)
})
.catch(error => {
this.setState({fetching: false})
console.log(error);
})
})
.catch(error => {
this.setState({fetching: false})
console.log(error)
})
}
render() {
const state = this.state;
const fetching = this.state.fetching;
const cart = this.state.cart;
const address = this.state.address;
const submittable = (cart.banana !== 0 || cart.cucumber !== 0) && state.email && state.name && address.line1 && address.city && address.state && address.country && address.postal_code
return (
<form onSubmit={this.handleSubmit} style={{width: '550px', margin: '20px', padding: '10px', border: '2px solid lightseagreen', borderRadius: '10px'}}>
<div>
Banana {(prices.banana / 100).toLocaleString('en-US', {style: 'currency', currency: 'usd'})}:
<div>
<button name={"banana"} value={1} onClick={this.handleCartChange}>+</button>
<button name={"banana"} value={-1} onClick={this.handleCartChange} disabled={cart.banana <=0}>-</button>
{cart.banana}
</div>
</div>
<div>
Cucumber {(prices.cucumber / 100).toLocaleString('en-US', {style:'currency', currency:'usd'})}:
<div>
<button name={"cucumber"} value={1} onClick={this.handleCartChange}>+</button>
<button name={"cucumber"} value={-1} onClick={this.handleCartChange} disabled={cart.cucumber <=0}>-</button>
{cart.cucumber}
</div>
</div>
<button onClick={this.handleCartReset}>Reset Cart</button>
<div style={{width: '450px', margin: '10px', padding: '5px', border: '2px solid green', borderRadius: '10px'}}>
<CardElement style={{base: {fontSize: '18px'}}}/>
</div>
<div>Name: <input type="text" name="name" onChange={this.handleChange}/></div>
<div>Email: <input type="text" name="email" onChange={this.handleChange}/></div>
<div>Address Line: <input type="text" name="line1" onChange={this.handleAddressChange}/></div>
<div>City: <input type="text" name="city" onChange={this.handleAddressChange}/></div>
<div>State: <input type="text" name="state" onChange={this.handleAddressChange}/></div>
<div>Country: <input type="text" name="country" onChange={this.handleAddressChange}/></div>
<div>Postal Code: <input type="text" name="postal_code" onChange={this.handleAddressChange}/></div>
<div>Coupon Code: <input type="text" name="coupon" onChange={this.handleChange}/></div>
{!fetching ?
<button type={'submit'} disabled={cart.banana=== 0 && cart.cucumber===0}>Purchase</button>
: 'Purchasing...'
}
Price: {((cart.banana * prices.banana + cart.cucumber * prices.cucumber) / 100).toLocaleString('en-US', {style: 'currency', currency: 'usd'})}
</form>
);
}
}
Shop.propTypes = {
stripe: PropTypes.shape({
createToken: PropTypes.func.isRequired}).isRequired
};
export default injectStripe(Shop)
【问题讨论】:
-
这是您从 Stripe 还是从您自己的 Express 服务器收到的错误?请注意,您的 axios 请求中有一个无效的 url:
http:localhost...应该是http://localhost...
标签: javascript node.js reactjs stripe-payments integration