Laravel по-русски

Русское сообщество разработки на PHP-фреймворке Laravel.

Ты не вошёл. Вход тут.

#1 05.12.2017 16:08:44

многократн. нажатие "Отправить" пишет в БД. кто как боролся?

(лара 5.5)
Собственно 5 раз нажмем кнопку "Отправить" и 5 раз данные из формы летят в БД. редирект на эту же страницу даже не успевает отработать.
Кто как с этим боролся? (с аяксом все понятно..)

Не в сети

#2 05.12.2017 17:48:04

TrueKanonir
Откуда: Ташкент
Сообщений: 179

Re: многократн. нажатие "Отправить" пишет в БД. кто как боролся?

$('form').on('submit', function() {
  $(this).find('.js-submit').prop('disabled', true);
});

Как варриант


Black / Thrash / MDM / Old-School Death...

Не в сети

#3 05.12.2017 18:33:44

Re: многократн. нажатие "Отправить" пишет в БД. кто как боролся?

$('form').on('submit', function() {
  $(this).find('.js-submit').prop('disabled', true);
});


Как варриант

Собственно, это и единственный вариант. Блокировать повторную отправку, пока предыдущий результат не пришел. Только лучше блокировать не кнопку, а саму форму (нажатие на enter никто не отменял).

Не в сети

#4 05.12.2017 18:37:09

TrueKanonir
Откуда: Ташкент
Сообщений: 179

Re: многократн. нажатие "Отправить" пишет в БД. кто как боролся?

  1. Только лучше блокировать не кнопку, а саму форму (нажатие на enter никто не отменял)

Действительно. Не прдумал как то об этом)


Black / Thrash / MDM / Old-School Death...

Не в сети

#5 05.12.2017 21:57:59

Re: многократн. нажатие "Отправить" пишет в БД. кто как боролся?

Собственно, это и единственный вариант.

Совершенно не единственный и даже не лучший:

  1. Если форма/кнопка блокируется, то ее нужно и разблокировать по какому-то событию (не факт, что форма вообще дойдет до сервера и соединение не порвется, нужно обрабатывать ошибки и тайм-аут).

  2. В Firefox (раньше, как сейчас не знаю) блокировка кнопки сохранялась при перезагрузке страницы по F5 (!).

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

Могут быть и другие неожиданности. Плюс у такого подхода только один - простота реализации. И еще, пожалуй, понятность для пользователя, если блокировку формы сопровождать сообщением вроде "форма отправляется, подождите".

Поэтому лучший вариант - это дополнительно проверять дубликат на стороне сервера. Это делается двумя способами в зависимости от ситуации:

  1. Если функция позволяет однозначно определить дублирование сообщения (или другой сущности, которая отправляется через форму) - например, заполнение анкеты, которую можно заполнить только один раз (у анкеты есть идентификатор, который передается из формы), голосование (тоже только один раз, тоже по некоему ID) и т.д. - то все просто: перед вставкой в БД проверяется наличие объекта. Или даже не проверяется, если в БД есть соответствующий уникальный ключ (UNIQUE), но тогда нужно показать осмысленное сообщение об ошибке, если вставка не пройдет.

  2. В других случаях в форму добавляется случайно сгенерированный ID, заносится в базу (в Redis, что оптимально, т.к. данные временные, либо в отдельную таблицу, либо в ту же таблицу, что и сами данные формы, в отдельном поле вроде duplicate_code), и при обработке запроса делается проверка на существование этого ID. Есть - значит, форма уже была принята и обработана.

В обоих случаях нужно учесть возможную гонку (race conditions), т.е. вставлять в базу ID перед обработкой операции в транзакции, чтобы при двух одновременных запросах не получилось так, что код проверил отсутствие ID в базе, и первый, и второй запросы пошли обрабатываться дальше, но в итоге один из них вернулся с ошибкой, когда пришло время добавлять данные в таблицу - первый запрос уже успел это сделать и занять ID, что для второго непредвиденная ситуация, ведь ID им уже был проверен. Или не вернулся с ошибкой, а все равно добавил дубль, не смотря на наличие кода.

-----------

По-четному, остается еще один вопрос: а какую из версий данных считать правильной - ту, что пришла раньше и уже была обработана, или повторную (что логично - позже отправили, значит, актуальнее)? Здесь все сложнее - на порядок запросов полагаться нельзя (тот что пришел первым вполне мог быть отправлен позже второго). Например, при отправке сообщения на форуме, при задержках в сети пользователь вполне может успеть нажать "Отправить", отменить, подредактировать что-то и снова "Отправить" - на всё секунд 10. И в каком порядке такие запросы придут на сервер - не известно.

Можно пойти простым путем (на мой взгляд, подходит в большинстве случаев): игнорировать все, что пришло после первого запроса. Если же хочется большего и нужно затирать первоначально созданную сущность новыми данными (новым текстом, например), то можно положиться на время отправки формы, навесив на ее onsubmit JS, который будет выставлять значение скрытому полю с меткой времени при каждой отправке. Особо упорные личности могут попытаться взять время из пришедшего TCP-пакета... Впрочем, JS может быть отключен, а клиент - не поддерживать TCP Timestamps, но даже если не так, то в обоих случаях это время не монотонное и может прыгать.

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

Не в сети

#6 05.12.2017 22:09:01

Re: многократн. нажатие "Отправить" пишет в БД. кто как боролся?

Иными словами - реализовать мьютекс (в рамках клиента) на бэкенде своими силами.

Изменено covobo (05.12.2017 22:10:19)

Не в сети

#7 05.12.2017 22:22:41

Re: многократн. нажатие "Отправить" пишет в БД. кто как боролся?

Иными словами - реализовать мьютекс (в рамках клиента) на бэкенде своими силами.

Да. В зависимости от функции повторная обработка может быть опасна (повторное списание с баланса, платное обращение в техподдержку и т.д.). Никто же, надеюсь, не проверяет баланс перед покупкой только на стороне клиента? Здесь так же.

БД (бекенд) - это "последний страж", все важные проверки должны происходить на ней, а не на стороне клиента. JS - это только для удобства, чтобы не гонять лишние байты в случае заведомой ошибки в заполнении формы, например. Но не больше. Нельзя полностью полагаться на проверку той же формы на стороне клиента.

Не в сети

#8 06.12.2017 09:45:41

TrueKanonir
Откуда: Ташкент
Сообщений: 179

Re: многократн. нажатие "Отправить" пишет в БД. кто как боролся?

  1. Совершенно не единственный и даже не лучший:

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


Black / Thrash / MDM / Old-School Death...

Не в сети

Подвал раздела