条纹:必须提供来源或客户 [英] Stripe: Must provide source or customer

查看:98
本文介绍了条纹:必须提供来源或客户的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试将Stripe集成到我的购物车项目中。我无法提交结帐表单。我不断收到此错误消息:必须提供来源或客户。要么我没有正确设置我的Stripe帐户,要么我在我的javascript中缺少一些参数。我花了好几个小时才解决这个问题,但仍然无法理解。

I'm trying to integrate Stripe for my shopping cart project. I can't get my checkout form to submit. I keep getting this error message: "Must provide source or customer." Either I didn't set up my Stripe account correctly or I'm missing some parameters in my javascript. I've spent hours on this problem and still can't figure it out.

这是来自Stripe的日志:

Parsed Request POST Body

This is from Stripe's log:
Parsed Request POST Body

{
  "amount": "21000",
  "currency": "usd",
  "description": "Test Charge"
}

回复正文

{
  "error": {
    "type": "invalid_request_error",
    "message": "Must provide source or customer."
  }
} 

这是我的app.js

var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var expressHbs = require('express-handlebars');
var mongoose = require('mongoose');
var session = require('express-session');
var passport = require('passport');
var flash = require('connect-flash');
var validator = require('express-validator');
var MongoStore = require('connect-mongo')(session);

var routes = require('./routes/index');
var userRoutes = require('./routes/user');

var app = express();

mongoose.connect('localhost:27017/shopping');
require('./config/passport');

// view engine setup
app.engine('.hbs', expressHbs({defaultLayout: 'layout', extname: '.hbs'}));
app.set('view engine', '.hbs');

// uncomment after placing your favicon in /public
//app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(validator());
app.use(cookieParser());
app.use(session({
    secret: 'mysupersecret', 
    resave: false, 
    saveUninitialized: false,
    store: new MongoStore({ mongooseConnection: mongoose.connection }),
    cookie: { maxAge: 180 * 60 * 1000 }
}));
app.use(flash());
app.use(passport.initialize());
app.use(passport.session());
app.use(express.static(path.join(__dirname, 'public')));

app.use(function(req, res, next){
    res.locals.login = req.isAuthenticated();
    res.locals.session = req.session;
    next();
});

app.use('/user', userRoutes);
app.use('/', routes);

// catch 404 and forward to error handler
app.use(function(req, res, next) {
  var err = new Error('Not Found');
  err.status = 404;
  next(err);
});

// error handler
app.use(function(err, req, res, next) {
  // set locals, only providing error in development
  res.locals.message = err.message;
  res.locals.error = req.app.get('env') === 'development' ? err : {};

  // render the error page
  res.status(err.status || 500);
  res.render('error');
});

module.exports = app;

这是我的index.js:

var express = require('express');
var router = express.Router();
var Cart = require('../models/cart');

var Product = require('../models/product');

/* GET home page. */
router.get('/', function(req, res, next) {
    var successMsg = req.flash('success')[0];
    Product.find(function(err, docs) {
        var productChunks = [];
        var chunkSize = 3;
        for (var i = 0; i < docs.length; i += chunkSize) {
            productChunks.push(docs.slice(i, i + chunkSize));
        }
        res.render('shop/index', { title: 'Shopping Cart', products: productChunks, successMsg: successMsg, noMessages: !successMsg});
    });
});

router.get('/add-to-cart/:id', function(req, res, next) {
    var productId = req.params.id;
    var cart = new Cart(req.session.cart ? req.session.cart : {});

    Product.findById(productId, function(err, product){
        if (err) {
            return res.redirect('/');
        }
        cart.add(product, product.id);
        req.session.cart = cart;
        console.log(req.session.cart);
        res.redirect('/');
    });
});

router.get('/shopping-cart', function(req, res, next) {
    if (!req.session.cart) {
        return res.render('shop/shopping-cart', {products: null});
    }
    var cart = new Cart(req.session.cart);
    res.render('shop/shopping-cart', {products: cart.generateArray(), totalPrice: cart.totalPrice});
});

router.get('/checkout', function(req, res, next) {
    if (!req.session.cart) {
        return res.redirect('/shopping-cart');
    }
    var cart = new Cart(req.session.cart);
    var errMsg = req.flash('error')[0];
    res.render('shop/checkout', {total: cart.totalPrice, errMsg: errMsg, noError: !errMsg});
});

router.post('/checkout', function(req, res, next) {
    if (!req.session.cart) {
        return res.redirect('/shopping-cart');
    }
    var cart = new Cart(req.session.cart);
    var stripe = require("stripe")(
      "**hidden**"
    );

    stripe.charges.create({
      amount: cart.totalPrice * 100,
      currency: "usd",
      source: req.body.stripeToken,
      description: "Test Charge"
    }, function(err, charge) {
        if (err) {
            req.flash('error', err.message);
            return res.redirect('/checkout');
        }
        req.flash('success', 'Successfully bought product!');
        req.cart = null;
        res.redirect('/');
    });
});

module.exports = router;

这是我的checkout.js:

Stripe.setPublishableKey('**hidden**');

var $form = $('checkout-form');

$form.submit(function(event) {
    $('#charge-errors').addClass('hidden');
    $form.find('button').prop('disabled', true);
    Stripe.card.createToken({
      number: $('#card-number').val(),
      cvc: $('#card-cvc').val(),
      exp_month: $('#card-expiry-month').val(),
      exp_year: $('#card-expiry-year').val(),
      name: $('#card-name').val()
    }, stripeResponseHandler);
    return false;
});

function stripeResponseHandler(status, response) {
    if (response.error) { // Problem!

    // Show the errors on the form
    $('#charge-errors').text(response.error.message);
    $('#charge-errors').removeClass('hidden');
    $form.find('button').prop('disabled', false); // Re-enable submission

  } else { // Token was created!

    // Get the token ID:
    var token = response.id;

    // Insert the token into the form so it gets submitted to the server:
    $form.append($('<input type="hidden" name="stripeToken" />').val(token));

    // Submit the form:
    $form.get(0).submit();
  }
};

这是我的结帐表单(.hbs):

<div class="row">
  <div class="col-sm-6 col-md-6 col-md-offset-3 col-sm-offset-3">
    <h1>Checkout</h1>
    <h4>Your Total: ${{total}}</h4>
    <div id="charge-error" class="alert alert-danger {{# if noError}}hidden{{/if}}">
        {{errMsg}}
    </div>
    <form action="/checkout" method="post" id="checkout-form">
      <div class="row">
          <div class="col-xs-12">
            <div class="form-group">
              <label for="name">Name</label>
              <input type="text" id="name" class="form-control" required>
            </div>
          </div>
          <div class="col-xs-12">
            <div class="form-group">
              <label for="name">Address</label>
              <input type="text" id="address" class="form-control" required>
            </div>
          </div>
          <div class="col-xs-12">
            <div class="form-group">
              <label for="name">Name on Card</label>
              <input type="text" id="card-name" class="form-control" required>
            </div>
          </div>
          <div class="col-xs-12">
            <div class="form-group">
              <label for="name">Credit Card Number</label>
              <input type="text" id="card-number" class="form-control" required>
            </div>
          </div>
          <div class="col-xs-6">
            <div class="form-group">
              <label for="name">Expiration Month</label>
              <input type="text" id="card-expiry-month" class="form-control" required>
            </div>
          </div>
          <div class="col-xs-6">
            <div class="form-group">
              <label for="name">Expiration Year</label>
              <input type="text" id="card-expiry-year" class="form-control" required>
            </div>
          </div>
          <div class="col-xs-12">
              <div class="form-group">
              <label for="name">
              CVC</label>
              <input type="text" id="card-cvc" class="form-control" required>
              </div>
          </div>
      </div>
      <button type="submit" class="btn btn-success">Buy Now</button>
    </form>
  </div>
</div>

<script type="text/javascript" src="https://js.stripe.com/v2/"></script>
<script type="text/javascript" src="javascripts/checkout.js"></script>


推荐答案

使用Stripe的付款流程分为两个步骤:

A payment flow with Stripe is divided in two steps:


  1. 客户端,在您的前端代码中,您使用结帐元素然后将生成的令牌发送到后端服务器。

  1. Client-side, in your frontend code, you collect and tokenize the customer's payment information using Checkout or Elements, then send the resulting token to your backend server.

服务器端,在后端代码中,您在API请求中使用令牌,例如创建费用客户

Server-side, in your backend code, you use the token in an API request, e.g. to create a charge or a customer.

您分享的代码是第一步。但是,您提到的错误消息:

The code you shared is for the first step. However, the error message you mentioned:


必须提供来源或客户。

Must provide source or customer.

在第二步中发生。当您在没有费用创建请求时,Stripe的API会返回此错误https://stripe.com/docs/api#create_charge-source\"rel =noreferrer> 来源 customer 参数。

occurs in the second step. This error is returned by Stripe's API when you send a charge creation request without a source or customer parameter.

您需要检查服务器端代码以确定问题的确切原因。您还可以在信息中心中查看集成发送的所有请求的日志: https:// dashboard.stripe.com/test/logs?method=not_get

You need to check your server-side code to figure out what the problem is exactly. You can also check the logs of all requests sent by your integration in your dashboard: https://dashboard.stripe.com/test/logs?method=not_get.

这篇关于条纹:必须提供来源或客户的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆