我正在尝试将Stripe集成到我的购物车项目中。我无法提交结帐表格。我不断收到此错误消息:“必须提供来源或客户。” 我没有正确设置我的Stripe帐户,或者我的JavaScript中缺少某些参数。我已经花了几个小时解决这个问题,但仍然无法解决。
这来自Stripe的日志: 解析的请求POST正文
{ "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的付款流程分为两个步骤:
在客户端,您可以使用Checkout或Elements在前端代码中收集并标记客户的付款信息,然后将生成的令牌发送到后端服务器。
在服务器端,在后端代码中,您可以在API请求中使用令牌,例如创建费用或客户。
您共享的代码是第一步。但是,您提到的错误消息:
必须提供来源或客户。
发生在第二步。当您发送不带或参数的费用创建请求时,Stripe的API返回此错误。sourcecustomer
source
customer
您需要检查服务器端代码以找出问题所在。您还可以在仪表板中查看集成发送的所有请求的日志:https : //dashboard.stripe.com/test/logs?method=not_get。