0

我创建了一个集成了 Stripe 以接受卡付款的 Android 移动应用程序。在我的 Android 应用程序中,我向我的 Laravel API 发送了一堆参数,其中一个是 Stripe 令牌。

10 次中有 9 次,我的服务器按预期处理。它将使用 Stripe-Cartalyst 创建一个收费对象并创建一个收费,假设没有抛出异常(例如错误的卡详细信息或服务器错误),然后我的 api 将继续处理支付成功并进行一些插入一个数据库,之后它将向客户端返回一个 201 HTTP 状态代码,然后我在 Android 端处理它。

我遇到的错误(或我做错的事情)是随机发生的。有时我的 API 会从 Stripe 抛出一个未捕获的异常,解释一个令牌(加密的 Stripe 卡详细信息),只能使用一次。我在 Android 端做了一些调试,可以验证我只在发送令牌的地方发出 1 个 HTTP 请求,并且在我的 Laravel API 上做了一些日志记录,并且发现了一些奇怪的事情。

在 API 上的发现,我将流程的一些关键时刻打印到了日志文件中。

  1. 打印令牌变量。
  2. 当进入try块创建charge对象时。
  3. 如果在 Android 应用上选择了“交付”(此处可能是毫无意义的日志)。
  4. 检查一些项目(这是从 Android 应用程序传递的数组。
  5. 在充电结束时,在将 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:创建 Stripe Charge

[2018-12-17 11:11:59] local.DEBUG:令牌:tok_1DiK0uKIdjSiVG8mn8CV2iim

[2018-12-17 11:11:59] local.DEBUG:创建 Stripe Charge

[2018-12-17 11:12:00] local.ERROR:目前有另一个正在进行的请求使用此 Stripe 令牌(这可能意味着您单击了两次,而其他费用仍在进行中):tok_1DiK0uKIdjSiVG8mn8CV2iim。如果该收费成功,则该令牌不能再次使用。{"exception":"[object] (Cartalyst\Stripe\Exception\MissingParameterException(code: 400): 当前有另一个正在进行的请求使用此 Stripe 令牌(这可能意味着您单击了两次,而另一个费用仍在进行中)通过):tok_1DiK0uKIdjSiVG8mn8CV2iim。如果收费成功,此令牌将无法再次使用。' at /home/rbfs6nkk73qi/api/prototype/vendor/cartalyst/stripe/src/Exception/Handler.php:123)[stacktrace]

[2018-12-17 11:12:00] local.DEBUG: 发货单

[2018-12-17 11:12:00] local.DEBUG:检查单项

[2018-12-17 11:12:00] local.DEBUG: Card delivery - Order through Android V0.5 app

这表明从我列出的 1-5 的步骤中,API 做了:1,2,1,2,error,3,4,5。

我完全不知道为什么我的 API 会随机运行两次。我在下面粘贴了我的 API 的相关部分,以查看我正在做的事情是否明显错误。感谢您对此的任何帮助。

我尝试过的最后一件事:我尝试在创建充电对象后直接将$token变量设置为,这让我想知道这是否是一些.null$stripeCartalyst 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');
            }
}
4

1 回答 1

0

经过进一步调试,找到了解决办法。事实证明,我在 Android 端使用的名为 Volley 的 HTTP 库不止一次发送请求。

将 Volley 请求设置为 0 次重试似乎已经解决了这个问题:

MyStringRequest.setRetryPolicy(new DefaultRetryPolicy(0,DefaultRetryPolicy.DEFAULT_MAX_RETRIES,DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));
于 2018-12-18T10:01:44.793 回答