Laravel — Эффективно ли мое решение для двойной отправки

#php #laravel

#php #laravel

Вопрос:

Это мой первый вопрос, поэтому, пожалуйста, отнеситесь ко мне полегче. Я уже некоторое время использую Laravel; однако недавно я столкнулся с проблемой в клиентском приложении во время его тестирования.

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

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

Тем не менее, эта форма (или, если быть точным, модель) допускает данные с одинаковыми значениями / дубликатами (требование клиентского приложения).

Итак, первое, что я сделал, было следующим:

 public function store(CustomRequest $request)
{
    if($lastEntry = Record::latest()->first()){
        if(
            ($request->name == $lastEntry->name)
            amp;amp; ($request->another == $lastEntry->another)
            //  amp;amp; ($request->user()->id == $lastEntry->user_id) // Current user check (need to modify the $lastEntry for it to work efficiently!)
            amp;amp; (now()->diffInMinutes($lastEntry->created_at) < 5) // I added this later as another way to allow duplicates records after each other if they were created 5m apart
        ){
            return redirect()
                    ->route('show.record', $lastEntry->id)
                    ->with('success', 'Record has been created successfully.');
        }
    }

    $record= new Record();
    ....
}

  

Теперь, после тестирования, оно отлично работает. Но, мой вопрос в том, существуют ли какие-либо встроенные решения для этого, пакеты или просто лучшие?

Кроме того, должен ли я использовать сессионное решение для более быстрого ответа — потому что, поправьте меня, если я ошибаюсь, но не будет ли это медленным, если оно было в таблице с> 500 тыс. записей?

Редактировать: Я думал о создании пользовательского промежуточного программного обеспечения throttle для этого, но это было бы своего рода плохой идеей, как вы думаете?

Кроме того, как упоминалось @nice_dev, при большем количестве пользователей произойдет удвоение, поэтому я подумал о добавлении поля user_id в таблицу записей и взял последнюю запись, созданную текущим пользователем, но все же я думаю, что это плохое решение.

Решение Javascript, к сожалению, не сокращает его

Редактировать: То, что я имел в виду под решениями на Javascript, — это известное после нажатия кнопки отключение такого рода решений (любых решений на стороне клиента).

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

Не стесняйтесь изменять мой вопрос по своему усмотрению… как я уже сказал, я здесь новичок!.

Заранее спасибо

Комментарии:

1. То, что подразумевается под решением javascript, к сожалению, не сократит его ?

2. Если вы не находитесь в среде «без JavaScript», это действительно окажет большую помощь; вы можете отключить кнопку отправки после ее нажатия.

3. Кроме того, ваше текущее решение на самом деле не решает проблему, поскольку другие пользователи могут одновременно вносить записи со своих компьютеров. Это latest() не обязательно даст тот же результат, и пользователь все равно может отправить снова. Поэтому просто отключите кнопку отправки до завершения запроса. Возможно, вы захотите использовать какие-то переменные сеанса, чтобы сделать его более надежным.

4. @Ali Вы можете создать индексацию в столбце FK для повышения производительности.

5. @nice_dev отличная идея, спасибо!

Ответ №1:

Поскольку моя ситуация в некотором роде уникальна, я выбрал то же решение, но добавил столбец user_id в таблицу записей (FK). И проверил, была ли одна и та же запись создана одним и тем же пользователем за последние x минут (поскольку клиент хочет дублировать записи, но не допускает ошибок пользователей).

Тем не менее, я добавил код javascript для отключения кнопки на всякий случай. Клиент запросил серверное решение, а не клиентское. Но мог бы также добавить, что, поскольку я вроде как решил проблему (вроде как). Кроме того, я создал индексацию в столбце FK, как предложил @nice_dev.

Мне пришлось быстро придумать решение. Тем не менее, не стесняйтесь делиться своими идеями / решениями.

Спасибо!

Комментарии:

1. я не понимаю, почему вы отказались от решения CSRF (я знаю, что это не является его целью, но я думаю, что это сработает, поскольку пользователь хочет получить новый CSRF), но я бы посоветовал использовать DB::begin() amp;amp; DB::commit() в начале и в конце вашего кода, чтобы использовать транзакции, и поэтому не полагаться на время, чтобы проверить, существует ли уже FK amp; ID

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

3. @Berto99 идея транзакций кажется интересной, не уверен, сработает ли она. Но попробую, когда смогу. Вчера мне пришлось перейти на быстрое решение, потому что была запрошена демонстрация с исправлением. Что касается решения CSRF, форма, которую я использую, — POST и имеет ввод @ csrf, а также маршрут, установленный только для POST. Итак, CSRF уже существует, но, как я уже сказал, он работает не так, как вы думаете. Я ценю вас и всех, кто пытался помочь.