Я создал мобильное приложение для Android, в которое встроен Stripe для приема карточных платежей.В моем приложении для Android я отправляю в свой Laravel API набор параметров, одним из которых является токен Stripe.
9 раз из 10, мой сервер обрабатывает это, как и ожидалось.Он создаст объект начисления с помощью Stripe-Cartalyst и создаст начисление, при условии, что не будет выброшено никаких исключений (таких как неверные данные карты или ошибка сервера), затем мой API выполнит обработку платежа как успешную и выполнит некоторые вставки вБД, после которой он возвращает код состояния HTTP 201 обратно клиенту, где я затем обрабатываю его на стороне Android.
Ошибка (или что-то, что я делаю неправильно), с которой я столкнулся, происходит случайно.Иногда мой API выдает непонятное исключение из Stripe, объясняющее токен (зашифрованные данные карты Stripe), который можно использовать только один раз.Я выполнил некоторую отладку на стороне Android и могу убедиться, что я делаю только 1 HTTP-запрос, когда отправляю токен, выполнил некоторую регистрацию на моем Laravel API и обнаружил некоторые странные изменения.
Что я нашел В API я напечатал некоторые ключевые моменты процесса в файле журнала.
- Напечатайте переменную токена.
- Когдавход в блок try для создания объекта заряда.
- Если в приложении Android выбрано «Доставка» (возможно, здесь бессмысленный журнал).
- Проверка некоторых элементов (это массив, переданный изAndroid-приложение.
- В конце зарядки, перед возвратом 201 клиенту, распечатайте сообщение об успехе.
Затем я продолжил воссоздавать ошибкупосле примерно 20/30 заказов это произошло, и вот процесс, который произошел:
Сначала в приложении Android был отправлен следующий токен (и распечатан на консоль);
tok_1DiK0uKIdjSiVG8mn8CV2iim
После проверки этот HTTP-запрос был запущен только один раз, поэтому я не думаю, что это проблема с Android.
Далее, в файле журнала API произошло следующее:
2018-12-17 11:11:56] local.DEBUG: Токен: tok_1DiK0uKIdjSiVG8mn8CV2iim [2018-12-17 11:11:56] local.DEBUG: Создание заряда полосы
[2018-12-17 11:11:59] local.DEBUG: токен: tok_1DiK0uKIdjSiVG8mn8CV2iim
[2018-12-17 11:11:59] local.DEBUG: создание заряда полосы
[2018-12-17 11:12:00] local.ERROR: В настоящее время существует другой незавершенный запрос, использующий этот токен Stripe (это, вероятно, означает, что вы щелкнули дважды, а другой заряд все еще выполняется): tok_1DiK0uKIdjSiVG8mn8CV2iim.Этот токен не может быть использован снова, если этот заряд успешен.{"исключение": "[объект] (Cartalyst \ Stripe \ Exception \ MissingParameterException (код: 400): в настоящее время существует другой обрабатываемый запрос, использующий этот токен Stripe (это, вероятно, означает, что вы щелкнули дважды, а другой платеж все еще идетчерез): tok_1DiK0uKIdjSiVG8mn8CV2iim. Этот токен не может быть использован повторно, если этот заряд успешно выполнен.*
[2018-12-17 11:12:00] local.DEBUG: заказ на доставку
[2018-12-17 11:12:00] local.DEBUG: проверка отдельных элементов
[2018-12-17 11:12:00] local.DEBUG: Доставка карты - заказ размещен через приложение Android V0.5
Это показывает, что из перечисленных шагов 1-5, API сделал: 1,2,1,2, ошибка, 3,4,5.
Я в полной растерянности относительно того, почему мой API запускался случайным образом дважды. Я вставил соответствующуючасти моего API ниже, чтобы увидеть, если что-то явно не так, что я делаю. Оцените любую помощь по этому вопросу.
Последнее, что я попробовал: я попытался установить переменную $token
равной null
непосредственно после создания объекта заряда $stripe
, что заставляет меня задаться вопросом, является ли это Cartalyst bug
.
if($card) {
$token = $request->token; //Stripe token
Log::debug("Token: ".$token); //Step 1
try {
Log::debug("Creating Stripe Charge"); //Step 2
$stripe->charges()->create([
'currency' => $currency,
'amount' => $amount,
'source' => $token
]);
if(strcmp($delivery,"Delivery") == 0) {
Log::debug("Delivery order"); //Step 3
if($singleItems != null) {
Log::debug("Checking single items"); //Step 4
foreach($singleItems as $key => $value) {
$singleItem = DB::table('items')
->select('name','category','price')
->where('item_id', '=', $key)
->get();
foreach($singleItem as $item) {
DB::table('single_order_items')->insert(['order_number' => $id, 'item'=>$key, 'quantity'=>$value, 'name'=>$item->name, 'category'=>$item->category, 'price'=>$item->price]);
}
}
}
Log::debug("Card delivery - ".$description); //Step 5
return response("Order placed successfully", 201)
->header('Content-Type', 'text/plain');
}
} catch(\Cartalyst\Stripe\Exception\BadRequestException $e) {
//This exception will be thrown when the data sent through the request is mal formed.
$message = $e->getMessage();
Log::debug($message);
return response($message, 306)
->header('Content-Type', 'text/plain');
} catch(\Cartalyst\Stripe\Exception\UnauthorizedException $e) {
//This exception will be thrown if your Stripe API Key is incorrect.
$message = $e->getMessage();
Log::debug($message);
return response($message, 307)
->header('Content-Type', 'text/plain');
} catch(\Cartalyst\Stripe\Exception\InvalidRequestException $e) {
//This exception will be thrown whenever the request fails for some reason.
$message = $e->getMessage();
Log::debug($message);
return response($message, 308)
->header('Content-Type', 'text/plain');
} catch(\Cartalyst\Stripe\Exception\NotFoundException $e) {
//This exception will be thrown whenever a request results on a 404.
$message = $e->getMessage();
Log::debug($message);
return response($message, 309)
->header('Content-Type', 'text/plain');
} catch(\Cartalyst\Stripe\Exception\CardErrorException $e) {
//This exception will be thrown whenever the credit card is invalid.
$message = $e->getMessage();
Log::debug($message);
return response($message, 310)
->header('Content-Type', 'text/plain');
} catch(\Cartalyst\Stripe\Exception\ServerErrorException $e) {
//This exception will be thrown whenever Stripe does something wrong.
$message = $e->getMessage();
Log::debug($message);
return response($message, 311)
->header('Content-Type', 'text/plain');
}
}