Laravel не завершает метод контроллера по нескольким запросам

Я попытался решить проблему с многократным нажатием кнопки отправки с помощью ReCaptcha V3. Это вроде работает, поскольку вставка базы данных выполняется в контроллере только один раз, а в последующие раз она просто попадает в проверку, возвращая ошибку.

Проблема в том, что метод контроллера не выполняется полностью.

Например, если я несколько раз нажимаю кнопку отправки на странице электронной коммерции, в CheckoutController метод checkout не запускается полностью.

class CheckOutController extends Controller {

    public function checkout(Request $request) {
        // Some checkout Logic (insert into database)
        $this->validate($request, [
                'recaptcha' => ['required', new \App\Rules\Recaptcha]
            ]);
        if (Cart::content()->count() > 0) {
            foreach (Cart::content() as $cartItem) {
              $insert = new \App\Transaction;
              $insert->product_id = $cartItem->id;
              $insert->receipt_id = $cartItem->receipt_id;
              $insert->quantity = $cartItem->qty;
              $insert->price= $cartItem->price;
              $insert->save();
            }
         Cart::destroy(); //last part of checkout logic
        return view('finishCheckout');
        }
        return abort(404);  
    }
}

Поскольку я работаю локально, скорость выше, поэтому запрос повторяется через мой код, вставляя данные в мою базу данных.

Иногда запрос попадает в часть логики Cart:: destroy();, иногда - нет. Но я подозреваю, что в производственной среде код может остановиться в другом месте перед этой частью.

И он никогда не попадает в return view('finishCheckout');. Он просто повторяет тот же метод и не проходит проверку, возвращая меня обратно на страницу оформления заказа с ошибкой проверки.

Могу ли я что-нибудь сделать, чтобы убедиться, что либо весь метод запущен, либо полностью остановить его?

Редактировать: Обратите внимание, что это происходит только тогда, когда я нажимаю кнопку отправки несколько раз! Если бы я щелкнул по нему только один раз, метод работает правильно.

Какие-нибудь ошибки зарегистрированы где-нибудь?

apokryfos 12.10.2018 09:51

Я работаю с APP_DEBUG=true, но у меня нет ошибок в laravel.log относительно этого контроллера.

Victordb 12.10.2018 09:56

Не уверен, что это связано с вашей проблемой, но Cart::destroy; недействителен. Если вы собираетесь вызвать статический метод destroy, тогда вы хотите сделать Cart::destroy();

Jonathon 12.10.2018 09:57

Да, в моем коде есть Cart::destroy(). Я написал это здесь неправильно, извините.

Victordb 12.10.2018 09:59

Было бы полезно, если бы вы могли поделиться кодом, который не работает или, просто добавьте много журналов после каждой строки, чтобы определить, что запускается и где останавливается.

apokryfos 12.10.2018 09:59

Я написал код, который не работает. Только Cart::destroy(); //last part of checkout logic return view('finishCheckout'); выходит из строя, а все остальное работает правильно. И Cart :: destroy () дает сбой только иногда и не всегда.

Victordb 12.10.2018 10:00
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Установка и настройка Nginx и PHP на Ubuntu-сервере
Установка и настройка Nginx и PHP на Ubuntu-сервере
В этот раз я сделаю руководство по установке и настройке nginx и php на Ubuntu OS.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Как установить PHP на Mac
Как установить PHP на Mac
PHP - это популярный язык программирования, который используется для разработки веб-приложений. Если вы используете Mac и хотите разрабатывать...
0
6
204
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Перед удалением use \Cart

Можно использовать Cart::delete() or Cart::where(....)->delete()

destroy()delete(), как бы вы ни называли его, не является проблемой. Иногда этот метод (destroy() в моем случае) работает, иногда нет. Но это не ошибка метода, после нескольких отправок формы запрос не ждет завершения метода и вместо этого выполняет новый запрос. Если бы мне нужно было сделать только один щелчок по кнопке отправки, метод checkout работает правильно.

Victordb 12.10.2018 10:20

Может быть, корзина пуста

Steve Boo 12.10.2018 10:44
Cart::destroy(); - это команда пустой корзины, и она не работает, когда я нажимаю кнопку отправки несколько раз. Работает только если щелкнуть один раз.
Victordb 12.10.2018 10:56

Лучшим решением было бы предотвратить двойной щелчок на стороне клиента. сделать функцию javascript, которая onSubmit отключает кнопку отправки.

Таким образом, пользователь получит ответ на первый сделанный им вызов, а не на последний (в случае двойной отправки).

Кстати, вы можете имитировать медленный сервер. просто добавьте sleep(3) в начало метода контроллера.

С sleep(3) у меня такая же проблема: код не работает в одной строке, НО только при отправке нескольких форм. Я хотел узнать, почему это происходит, прежде чем пытаться решить эту проблему на стороне клиента.

Victordb 12.10.2018 10:36

Первый запрос: checkout_logic + cart_destroy. Второй запрос: checkout_logic_with_no_cart (потому что он был уничтожен) -> ошибка

N69S 12.10.2018 10:52

Первый запрос не выполняет cart_destroy, когда я нажимаю кнопки отправки несколько раз. Вот в чем проблема. Если я нажму кнопку отправки, как только он правильно выполнит cart_destroy.

Victordb 12.10.2018 10:55

@Victordb то, что вы говорите, противоречиво, можете ли вы указать на свой вопрос полный код checkout?

N69S 12.10.2018 10:56

Я добавил кое-что, имеющее отношение к вопросу. Хотя это не проблема с кодом, поскольку он отлично работает, когда я отправляю форму только один раз. Проблема в том, что я нажимаю кнопки отправки несколько раз.

Victordb 12.10.2018 11:02

Как я уже сказал, результат, который вы получаете при многократной отправке, - это последний запрос (404 100%). первый работал правильно.

N69S 12.10.2018 11:18

Первый не выполняет Cart::destroy();. У меня все еще есть продукты в тележке, когда меня перенаправляют обратно с ошибкой проверки. Когда я отправляю форму одним щелчком мыши, Cart::destroy(); правильно опорожняет корзину. Но когда я отправляю с несколькими щелчками мыши, Cart::destroy(); происходит не только с кодом над ним.

Victordb 12.10.2018 11:23

Позвольте нам продолжить обсуждение в чате.

N69S 12.10.2018 11:36

Моя теория заключается в том, что, поскольку вы нажимаете кнопку несколько раз, в одном из запросов он выполняет итерацию по содержимому корзины, а затем достигает метода Cart::destroy(), но затем по другим запросам, поскольку это уже было так, он не выполняет условное и прыгает прямо к функции abort(404).

Если вы делаете запрос с помощью Ajax, меня это не удивляет. В случае асинхронных HTTP-запросов, если вы снова нажмете кнопку, он создаст новый запрос и позволит продолжить выполнение предыдущего, а не отменит его. Это должен быть ваш внешний интерфейс, который при нажатии кнопки во время выполнения запроса отключает кнопку, поэтому дальнейшие запросы не могут быть выполнены.

Я не делаю запрос с помощью Ajax, и проблема в том, что первый запрос ОСТАНАВЛИВАЕТСЯ прямо перед Cart::destroy(). Таким образом, первый запрос проходит через код (вставляется в базу данных) и по какой-то причине останавливается прямо на Cart::destroy().

Victordb 12.10.2018 13:37

Возможно возникновение исключения. Проверьте журналы и посмотрите, есть ли там что-нибудь. Вы также можете обернуть вставки в транзакцию базы данных, чтобы в случае исключения она возвращала вставки базы данных.

George Hanson 12.10.2018 14:19
Ответ принят как подходящий

Решено с использованием транзакций php, например:

class CheckOutController extends Controller {

    public function checkout(Request $request) {
        // Some checkout Logic (insert into database)
        $this->validate($request, [
        'recaptcha' => ['required', new \App\Rules\Recaptcha]
        ]);

        DB::beginTransaction();
        try {
            if (Cart::content()->count() > 0) {
                foreach (Cart::content() as $cartItem) {
                    $insert = new \App\Transaction;
                    $insert->product_id = $cartItem->id;
                    $insert->receipt_id = $cartItem->receipt_id;
                    $insert->quantity = $cartItem->qty;
                    $insert->price= $cartItem->price;
                    $insert->save();
                }
            }
            DB::commit();
            Cart::destroy();
            return view('finishCheckout');
        } catch (\Exception $e) {
            DB::rollback();
            return view('errorView')->withErrors($e->getMessage());
        }
            return abort(404);
    }
}

Другие вопросы по теме