【问题标题】:How can I make a https request to Stripe API with Axios?如何使用 Axios 向 Stripe API 发出 https 请求?
【发布时间】: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


【解决方案1】:

您不能从客户端对 Stripe 进行服务器端 API 调用,并且您永远不应该(永远[永远])将您的密钥放在客户端代码中。

您需要使用某种服务器端代码来完成该部分,或使用client-only Checkout

【讨论】:

  • 我想我找到了一个解决方案,即使用 Firebase Functions 对 Stripe 进行 API 调用。我正在研究如何做到这一点,所以如果你有 firebase 功能方面的专业知识,请告诉我!
猜你喜欢
  • 1970-01-01
  • 2021-11-12
  • 2020-11-05
  • 1970-01-01
  • 2022-01-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-10-30
相关资源
最近更新 更多