| Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
| Форум программистов > PHP: Общие вопросы > Повторная отправка формы. |
| Автор: matrixphp 3.11.2012, 03:45 |
| Новостной сайт (написан по PHP). Сервер (LAMP) старенький , часто бывает перегружен и сайт начинает тормозить или просто сильно удален от пользователя, из-за чего тоже возникает задержка. Пользователь прочитал новостную статью и решил оставить комментарий. Заполнил форму и нажал отправить, но т.к. сервер тормозит страница обновилась не сразу и пользователь еще несколько раз пытается создать комментарий (отправлял форму). В итоге он несколько раз создал один и тот же комментарий. Подскажите, пожалуйста, как можно избежать повторной обработки запроса, чтобы, если опираться на данный пример, создавался только 1 комментарий. |
| Автор: ksnk 3.11.2012, 06:34 |
| matrixphp, Вставлять в форму скрытое поле-ключ. При каждом открытии формы комментария поле должно быть разным, например - таймстамп времени генерации страницы. При добавлении комментария проверяется, что комментарий с таким ключом еще не добавлен. |
| Автор: matrixphp 3.11.2012, 13:36 |
| Вроде это решает проблему, но как быть с другими формами. Добавление коммента это лишь частный случай, ведь такое возможно практически с любой формой... Как-то не комельфо хранить в бд ключи всего чего творит пользователь |
| Автор: 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 проблемой не борются, обычно. Считается, что интернет велик, могуч и быстр. Если он не быстр - юзер все равно не будет долго сидеть на таком сайте, так что и возится нет смысла Добавлено через 3 минуты и 26 секунд Про сессию я уже говорил. Стоит ли оно того, чтобы заставлять юзера не отходить от компьютера на "попить пива с друзьями"? При большом количестве форм (объектов комментирования), нужно будет большое количество кук. Или одну большую куку со всеми ключиками в одну строку, разделенную запятыми... |
| Автор: 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:49 | ||
JS поможет, но не везде. Есть запросы которые посылаются ссылкой без заполнения формы (location.href='...') и выстраивать js в каждую такую ссылку не очень удобно. Это я понимаю, потому и написал про упорный клик. Все-таки вероятно сервер успеет частично обновить страницу, а кука вроде придет даже до заголовка. Или все-таки я ошибаюсь с кукой? |
| Автор: Fortop 4.11.2012, 01:31 | ||
Если он успевает частично обновить страницу, то редирект поможет (он как ни странно приходит вместе с куками в заголовке) Если он не успевает, то поле как выше обсуждалось или js-ом чистить формы
Какое отношение это имеет к сабмиту формы? |
| Автор: MoLeX 4.11.2012, 08:15 |
| и почему самое просто решение не кто не предложил? после сообщения делать таймаут (скажем секунд 10), после которого нельзя отправлять новые сообщения. сразу убиваем двух зайцев |
| Автор: ksnk 4.11.2012, 08:39 | ||
Это кто не предложил?
Я капу вовремя нажал |
| Автор: matrixphp 4.11.2012, 14:32 |
| Всем спасибо. Сделал через сессия + куки - пока все работает. Будут шалить придется использовать JS и БД. |
| Автор: MoLeX 4.11.2012, 19:41 |
| ksnk, извиняй, не приметил) |