Решение проблемы двойного представления - PullRequest
25 голосов
/ 15 января 2011

Я хотел бы увидеть, как веб-разработчики избегают проблемы двойной отправки. Итак, в основном мое понимание проблемы заключается в следующем:

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

Существуют также методы обнаружения на стороне сервера.

Итак, мои вопросы:

Как люди преодолевают двойное подчинение? Что является реальным примером проблемы, вызванной двойным подчинением? В какие-либо фреймворки веб-приложений встроены инструменты двойной отправки?

Ответы [ 7 ]

16 голосов
/ 16 января 2011

Ситуация в реальной жизни: размещение ставок на сайте ставок. Пользователи будут дважды щелкать и получать две ставки. Нехорошо! Проверок Javascript было недостаточно для предотвращения этого.

Решение:

  1. Создать UUID / GUID скрытый ввод в форму с использованием языка сценариев на стороне сервера, который отображает форму.

  2. При отправке формы немедленно добавьте это в таблицу базы данных с именем UniqueSubmissions (например). Затем приступите к обработке.

  3. Каждый последующий запрос с тем же UUID / GUID будет отклонен, если он найден в таблице UniqueSubmissions.

Это сработало для нас. Надеюсь, это поможет ответить на ваш вопрос!

8 голосов
/ 15 января 2011

Если вы работаете со сценариями на стороне сервера Java, а также используете Struts 2, то вы ссылаетесь на эту ссылку, в которой рассказывается об использовании токена.

http://www.xinotes.org/notes/note/369/

Необходимо создать токен исохраняется в сеансе для начальной визуализации страницы, когда запрос отправляется вместе с токеном в первый раз, при выполнении действия Struts запускает поток с именем потока в качестве идентификатора токена и запускает логику в соответствии с запросом клиента, когда клиент отправляетснова тот же запрос, проверьте, работает ли еще поток (thread.getcurrentthread (). interrupted), если он все еще работает, затем отправьте клиентское перенаправление 503.

Пожалуйста, посмотрите на ExecuteAndWaitInterceptor Struts 2code, логику этогов сочетании с токеном поможет быстрый клик

7 голосов
/ 15 января 2011

Используйте redirect-after-post или иногда называют PRG (post / redirect / get)

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

5 голосов
/ 15 января 2011

Примером из реальной жизни может быть ответ на этот вопрос дважды ;-).Если вы не хотите полагаться на какой-либо аспект клиентской стороны (javascript или даже cookie-файлы), вы можете рассчитать MD5-хеш представленных данных, возможно, добавив такую ​​информацию, как IP-адрес источника и используемый браузер, и отклонить сообщенияс одинаковым хешем.

3 голосов
/ 06 февраля 2011

Фреймворк web2py имеет встроенную защиту от двойной отправки формы.Он хранит одноразовый токен в сеансе, а также в скрытом поле формы, и они должны совпадать при отправке, иначе отправка отклоняется.Этот метод также защищает от CSRF (подделка межсайтовых запросов).

2 голосов
/ 15 января 2011

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

1 голос
/ 13 августа 2015

Используя каркас веб-приложения Struts, мы можем решить эту проблему следующим образом:

В Struts есть 3 метода, используемых для token, saveToken(), isTokenValid() and resetToken().

saveToken() - сгенерировать ключ токена и сохранить в атрибуте request / session.
isTokenValid() - проверить отправленный ключ токена по 1 хранилищу в запросе / сеансе.
resetToken() - сбросключ токена

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

<form action="myaction.do" method="post"> 
 <input type="hidden" 
 name="<%= Constants.TOKEN_KEY %>" 
 value="<%= session.getAttribute(Action.TRANSACTION_TOKEN_KEY) %>" > 

2) После отправки формы вызывает isTokenValid() в классе действия он будет проверять отправленный ключ токена (скрытое поле) с ключом токена, сохраненным ранее по запросу / сеансу.Если совпадение, он вернет истину.

public final ActionForward perform(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {
    saveToken(request);
    if (!tokenIsValid(request)) {
        //forward to error page saying "your transaction is already being processed" 
    } else {
        //process action 
        //forward to jsp 
    }
    // Reset token after transaction success. 
    resetToken(request);
}

ссылка

...