Я сделал небольшое приложение для регистрации на мероприятие. Пользователь вводит свои данные и нажимает «войти».
Теперь иногда люди дублируются в базе данных, одни и те же данные вставляются 2 раза очень быстро друг за другом. Это может означать только, что кто-то дважды нажал кнопку, что привело к появлению двух сообщений.
Это обычная проблема в Интернете, поскольку приложения для кредитных карт и форумы часто говорят: «Достаточно одного щелчка!».
Я думаю, вы могли бы решить эту проблему, проверив те же самые данные, чтобы узнать, является ли сообщение уникальным, но мне интересно, есть ли другие методы.
Это, конечно, не учитывается для веб-форм ASP.NET, потому что POST не имеет большого значения.





Решение на стороне пользователя - отключить кнопку отправки через Javascript после первого щелчка.
У него есть недостатки, но я вижу, что его часто используют на сайтах электронной коммерции.
Но это никогда не заменит настоящую проверку на стороне сервера.
Это может быть полезным дополнением к обнаружению на стороне сервера, поскольку может остановить ваш второй щелчок, который приведет вас на страницу «Ты дважды опубликовал, идиот». Вскоре после этого рекомендуется повторно включить кнопку, чтобы предотвратить случайное двойное нажатие, не нарушая форму для преднамеренного повторного использования.
Изменение на стороне клиента - распространенный прием:
Но это не идеально. Все зависит от доступности JS, и если это не так, без обнаружения дублирования на сервере вы все равно будете получать дубликаты.
Так что мой совет - разработать какое-то скрытое обнаружение. а потом улучшит вашу форму, чтобы люди с JS не могли дважды отправлять.
Вы можете отслеживать количество отправок формы и сравнивать его с количеством уникальных посещений страницы с формой на ней в сеансе.
Пока что большинство ответов были на стороне клиента. На стороне сервера вы можете создать скрытое поле с идентификатором GUID при первом создании формы, а затем записать этот идентификатор GUID как отправленную форму при получении сообщения. Проверьте его перед дальнейшей обработкой.
Клиентская сторона +1 просто недостаточно надежна там, где возможно повреждение данных, особенно там, где так хорошо работает метод одноразового ключа
(на самом деле, просто хотел добавить, я лично предпочитаю помещать этот ключ в строку запроса, а не создавать скрытое поле)
GUID используется здесь как «ключ идемпотентности», чтобы дать любому, кто интересуется теорией, термин для поиска в Google.
Техники на стороне клиента полезны, но вы можете объединить их с некоторыми методами на стороне сервера.
Один из способов сделать это - включить в форму уникальный токен (например, GUID или аналогичный), чтобы при обработке формы вы могли проверить, был ли токен уже использован, что предотвратит двойную отправку.
В вашем случае, если у вас есть таблица с посетителями событий, вы можете включить этот токен в качестве столбца.
Хотя решения JavaScript могут отключать кнопку отправки после ее нажатия, это не повлияет на людей, у которых отключен JavaScript. Вы всегда должны заставить все работать правильно без JavaScript, прежде чем добавлять его, иначе нет смысла, поскольку пользователи все равно смогут обойти проверки, просто отключив JavaScript.
Если страница, на которой отображается форма, создается динамически, вы можете добавить скрытое поле, которое содержит какой-то порядковый номер, хэш или что-то уникальное. Затем у вас есть некоторая проверка на стороне сервера, которая проверяет, поступил ли уже запрос с этим уникальным значением. Когда пользователь отправляет форму, уникальное значение проверяется по списку «используемых» значений. Если он существует в списке, это ложный запрос, и от него можно отказаться. Если его нет, добавьте его в список и обработайте как обычно. Если вы убедитесь, что значение уникально, это гарантирует, что одна и та же форма не может быть отправлена дважды.
Конечно, если страница, на которой находится форма, не генерируется динамически, вам нужно будет сделать это жестким способом на стороне сервера, чтобы проверить, что та же информация еще не была отправлена.
Ваше решение проблемы в порядке. Но скрытое поле может быть просмотрено клиентом и может быть отредактировано им, чтобы испортить наше приложение, которое может снова принять двойную форму. Я ищу решение, полностью ориентированное на сервер.
Если у вас есть балансировщик нагрузки, отправьте на сервер UUID (или любой тип уникального номера) для сохранения и повторного чтения, это не сработает, если сервер не знает о других серверах, потому что каждый запрос может обрабатываться другим сервером. .
Привет, Рич Адамс. Я хотел воспроизвести проблему, заключающуюся в том, что если вы дважды нажмете кнопку, форма будет отправлена дважды. Однако этого никогда не происходит. Даже если я нажму кнопку 100 раз, форма будет отправлена только один раз - знаете ли вы, почему это работает из коробки? Вот мой пример: stackoverflow.com/questions/51347585/…
Помимо множества уже упомянутых хороших методов, еще один простой серверный метод, который имеет недостаток, заключающийся в необходимости сеанса, заключается в том, чтобы иметь переменную сеанса, которая отключается при первой отправке.
Как указано во многих ответах здесь, решения только для клиента будет недостаточно. Вам нужно использовать отказоустойчивый сервер на стороне сервера.
Часто игнорируемая причина, по которой отключение кнопки отправки не работает, заключается в том, что пользователь может просто обновить цель отправки (и нажать OK в диалоговом окне «Вы уверены, что хотите повторно отправить данные POST?»). Или даже некоторые браузеры могут неявно перезагружать отправленную страницу, когда вы пытаетесь сохранить страницу на диск (например, вы пытаетесь сохранить бумажную копию подтверждения заказа).
Я думал об этом, мы не можем предотвратить двойную отправку с помощью простого javascript.
Практически ни у кого нет отключенных js. Подумайте о написании кода для своего веб-сайта электронной коммерции для 70-летней женщины, которая дважды нажимает на каждую ссылку и кнопку. Все, что вам нужно сделать, это добавить javascript, чтобы она не нажимала «Заказать сейчас» дважды. Да - проверьте это и на стороне сервера, «будьте осторожны» - но не используйте код для этого случая. Но для улучшения пользовательского интерфейса сделайте это и на стороне клиента.
Вот несколько скриптов, которые я нашел:
//
// prevent double-click on submit
//
jQuery('input[type=submit]').click(function(){
if (jQuery.data(this, 'clicked')){
return false;
}
else{
jQuery.data(this, 'clicked', true);
return true;
}
});
а также
// Find ALL <form> tags on your page
$('form').submit(function(){
// On submit disable its submit button
$('input[type=submit]', this).attr('disabled', 'disabled');
});
Каждый раз, когда страница запрашивается с сервера, сгенерируйте уникальный requestToken, сохраните его на стороне сервера, пометьте статус как НЕ обработано и передайте его вместе с текущей запрошенной страницей. Теперь всякий раз, когда происходит отправка страницы, получите requestToken из данных «POST», проверьте статус и сохраните данные или выполните альтернативное действие.
Большинство банковских приложений используют эту технику для предотвращения двойной отправки сообщений "POST". Так что это проверенный временем и надежный способ предотвращения двойной отправки.
Черит, допустим, клиент получил токен и отправляет POST. POST сделал это на сервере, но на ответ, сеть пострадала. Пользователь не увидел ответа. Он обновляет страницу формы. Должен ли он получить новый токен после того, как его POST сделал это ранее?
@devwannabe, когда пользователь обновляет страницу, браузер в качестве любезности попросит повторно отправить данные формы. Браузер может отправлять те же данные формы, но сервер может отклонить их на основании истекшего токена. Если сервер не закодирован для проверки истекшего токена, это может привести к двойной отправке одних и тех же данных. Способ обработки токена с истекшим сроком действия - выполнить перенаправление на стороне сервера на другую страницу с сообщением, что «ваши данные уже отправлены» или, если это вызов ajax, ответ об ошибке соответственно. Его неофициально называют паттерном PRG. Подробнее -> theserverside.com/news/1365146/Redirect-After-Post
Это означает, что браузер может повторно отправлять те же данные, если серверная часть знает, как проверить отправленные данные. Бэкэнд должен всегда проверять, был ли запрос уже выполнен ранее, и если да, перенаправить пользователя на другую страницу.
Ни одно из решений не относится к серверу балансировки нагрузки.
Если у вас есть балансировщик нагрузки, отправьте UUID (или любой тип уникального номера) на сервер для сохранения и повторного чтения, это не сработает, если сервер не знает о других серверах, потому что каждый запрос может обрабатываться другим сервером. в среде без гражданства. Эти серверы должны читать / писать в одно и то же место.
Если у вас несколько серверов, вам понадобится общий кеш (например, Redis) между серверами для чтения / записи уникального значения в одном и том же месте (что может быть чрезмерно инженерным решением, но работает).
Также обратные прокси, такие как Kong, любят отправлять автоматические повторные попытки, когда ваш бэкэнд занимает слишком много времени. Один запрос, отправленный клиентом, будет отображаться как 5 отдельных запросов к бэкэнду. Это проблема, с которой мы однажды столкнулись при продакшене, и это было некрасиво.