Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > PHP: Общие вопросы > Повторная отправка формы.


Автор: matrixphp 3.11.2012, 03:45
Новостной сайт (написан по PHP). Сервер (LAMP) старенький , часто бывает перегружен и сайт начинает тормозить или просто сильно удален от пользователя, из-за чего тоже возникает задержка. Пользователь прочитал новостную статью и решил оставить комментарий. Заполнил форму и нажал отправить, но т.к. сервер тормозит страница обновилась не сразу и пользователь еще несколько раз пытается создать комментарий (отправлял форму). В итоге он несколько раз создал один и тот же комментарий. Подскажите, пожалуйста, как можно избежать повторной обработки запроса, чтобы, если опираться на данный пример, создавался только 1 комментарий.

Автор: ksnk 3.11.2012, 06:34
matrixphp, Вставлять в форму скрытое поле-ключ. При каждом открытии формы комментария поле должно быть разным, например - таймстамп времени генерации страницы. При добавлении комментария проверяется, что комментарий с таким ключом еще не добавлен.

Автор: matrixphp 3.11.2012, 13:36
Вроде это решает проблему, но как быть с другими формами. Добавление коммента это лишь частный случай, ведь такое возможно практически с любой формой... Как-то не комельфо хранить в бд ключи всего чего творит пользователь smile

Автор: ksnk 3.11.2012, 13:47
Можно хранить в сессии массив всех ключей всех отображенных у юзера форм за весь период жизни сессии. Кто знает этого юзера - на сколько статей-комментов он одновременно желает ответить?
Если прилетает тот, что есть в сессии - в сессии его помечаем удаленным. Если нету ключа - переспрашиваем узера, что он такое имел ввиду. Ключ помечен удаленным - спрашиваем у юзера - желает ли он заменить свой комментарий на более новый.


Автор: matrixphp 3.11.2012, 13:57
Как лучше сделать ключ?
Не слишком ли много информации для сессии, ведь проблема свойственна любым формам, если хранить такой массив там может быть не одна тысяча ключей?


Автор: Fortop 3.11.2012, 14:45
Можно после сабмита формы сразу делать редирект

Автор: ksnk 3.11.2012, 15:07
Вообразим себе блог с комментариями. Каждый комментарий в свою очередь может комментироваться. На каждой странице, примерно по 10-30 "объектов комментирования". Формочка ответа подставляется под кнопку Javascript'ом и не беспокоит сервер до момента своей отправки. После отправки, вся страница обновляется, оставив открытыми просматриваемые ветки. (можно обновлять только ветку, но принципиальной разницы нет)

Юзер пришел и открыл несколько страниц сайта с разными статьями и страницами комментариев. 
Юзер медленно читает все это добро и по мере появления мыслей кликает на кнопку "Ответить", заполняет формочку ответа и посылает ответ. Иногда - отвечает на то же самое второй и третий раз.

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

Итого, если мы храним ключи в сессии - у нас имеется проблема с юзерами, которые не успевают прочитать все 100++ открытых ими страниц за 10 минут, пока гарантированно жива сессия. Так что ключи нужно по любому хранить в базе. Можно для этого отрядить отдельную таблицу, которую периодически подчищать.

Для такой ситуации (наиболее общей, imho). 
-- Ключ должен состоять из ID юзера, Таймстампа времени генерации страницы и ID "объекта комментирования".

Добавлено через 1 минуту и 17 секунд
Fortop, рассматривается ситуация торможения сервера. Броузер не успевает обработать редирект до повторного нажатия на кнопку "отправить"

Автор: matrixphp 3.11.2012, 17:02
Создание подобного ключа, конечно решает вопрос.
Но проблема с заклиниванием форм (комменты лишь частный случай), по идее, должна быть актуально практически для всех сайтов и когда я создавал топ, считал, что существует некое универсальное общепризнанное решение...

Добавлено через 10 минут и 33 секунды
На основе ключей вот еще пара идей возникла:
В сессию записывать ключ и пользователю сообщать этот ключ через скрытое поле в форме. После отправки формы, перед записью данных обработки проверять совпадение ключей.
Проблему повторной отправки это решит, но если на сайте 100+ форм, переделывать это трудоемко...
Тогда можно попробовать передавать пользователю ключ кукой, но есть подозрения что все-таки особо упорные пользователи будут закликивать так (достаточной долго, чтобы сервер попытался, что-то отправить), что кука будет успевать обновляться и часть запросов пройдет.
Что скажете на такие предложения?

Автор: ksnk 3.11.2012, 17:34
C проблемой не борются, обычно. Считается, что интернет велик, могуч и быстр. Если он не быстр - юзер все равно не будет долго сидеть на таком сайте, так что и возится нет смысла  smile

Добавлено через 3 минуты и 26 секунд
Цитата(matrixphp @  3.11.2012,  17:02 Найти цитируемый пост)
В сессию записывать ключ

Про сессию я уже говорил. Стоит ли оно того, чтобы  заставлять юзера не отходить от компьютера на "попить пива с друзьями"?
При большом количестве форм (объектов комментирования), нужно будет большое количество кук. Или одну большую куку со всеми ключиками в одну строку, разделенную запятыми...

Автор: matrixphp 3.11.2012, 18:10
Цитата

не будет долго сидеть

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

Цитата

количестве форм

Я имел ввиду другое в целом по сайту разных форм много (настройки, комменты, рейтинги и многое другое, как в том же самом ВК). Добавление коммента это все-таки одна и также форма.

Цитата

будет большое количество кук

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

Автор: ksnk 3.11.2012, 19:28
Цитата(matrixphp @  3.11.2012,  18:10 Найти цитируемый пост)
Смысл же в том, чтобы после отправки одной любой формы сразу все формы на странице потеряли актуальность.

Не на одной странице, а на всех открытых страницах. В итоге - все страницы сайта, открытые в табах, придется перегружать. 

Автор: matrixphp 3.11.2012, 20:03
В данном случае получится так, что после отправки комментария в одной табе, другие теряют работоспособность. Да, это минус и тем не менее вопрос остается открытым:
"Кука будет успевать обновляться и часть запросов пройдет" или будет работать так же эффективно как со скрытым полем?
Ведь все-таки скрытое поле гарантирует, что пользователь не сможет повторно добавить комментарий пока не добавился предыдущий.

Автор: ksnk 3.11.2012, 20:24
Еще одно решение - javascript. Нажатие на кнопку отправки устанавливает куку на 10 секунд. В следующий раз при клике проверяем установлена ли кука, если установлена - говорим, что форма отослана, надо подождать. 

Цитата(matrixphp @  3.11.2012,  20:03 Найти цитируемый пост)
Кука будет успевать обновляться и часть запросов пройдет

Кука устанавливается при обновлении страницы, то есть прилетает от сервера в том же потоке данных, что и новая страница. Если страница не обновилась, то кука осталась старой.

Автор: matrixphp 3.11.2012, 20:49
Цитата

то кука осталась старой

JS поможет, но не везде. Есть запросы которые посылаются ссылкой без заполнения формы (location.href='...') и выстраивать js в каждую такую ссылку не очень удобно.
Это я понимаю, потому и написал про упорный клик. Все-таки вероятно сервер успеет частично обновить страницу, а кука вроде придет даже до заголовка.
Или все-таки я ошибаюсь с кукой?

Автор: Fortop 4.11.2012, 01:31
Цитата(matrixphp @  3.11.2012,  20:49 Найти цитируемый пост)
Все-таки вероятно сервер успеет частично обновить страницу

Если он успевает частично обновить страницу, то редирект поможет (он как ни странно приходит вместе с куками в заголовке)

Если он не успевает, то поле как выше обсуждалось или js-ом чистить формы

Цитата(matrixphp @  3.11.2012,  20:49 Найти цитируемый пост)
Есть запросы которые посылаются ссылкой без заполнения формы (location.href='...')

Какое отношение это имеет к сабмиту формы?

Автор: MoLeX 4.11.2012, 08:15
и почему самое просто решение не кто не предложил? 
после сообщения делать таймаут (скажем секунд 10), после которого нельзя отправлять новые сообщения.
сразу убиваем двух зайцев

Автор: ksnk 4.11.2012, 08:39
Цитата(MoLeX @  4.11.2012,  08:15 Найти цитируемый пост)
и почему самое просто решение не кто не предложил? 

Это кто не предложил?
Цитата(ksnk @  3.11.2012,  20:24 Найти цитируемый пост)
Еще одно решение - javascript. Нажатие на кнопку отправки устанавливает куку на 10 секунд. В следующий раз при клике проверяем установлена ли кука, если установлена - говорим, что форма отослана, надо подождать. 


Я капу вовремя нажал  smile 

Автор: matrixphp 4.11.2012, 14:32
Всем спасибо. Сделал через сессия + куки - пока все работает. Будут шалить придется использовать JS и БД.

Автор: MoLeX 4.11.2012, 19:41
ksnk, извиняй, не приметил)

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)