Как игнорировать несколько кликов от нетерпеливого пользователя?

У меня есть запрос для ответа на стандартный запрос удаленных клиентов. Стандарт в том смысле, что он не принимает никаких параметров извне сервера. Всякий раз, когда любой отправляет запрос на URL-адрес, скажем http://www.example.com/query, он/она получает содержимое reply.xml в теле ответа, в зависимости от того, что в данный момент предоставляет база данных. Содержимое reply.xml изменяется только по содержимому базы данных на сервере и не изменяется ни на что внешнее например, кто выполняет запрос, на котором ввод и т.д., следовательно, не принимает никаких параметров от клиентов. Я даже не проверяю аутентификацию - мы оставляем все на брандмауэре.

Итак, я написал метод @POST, скажем query(), чтобы вызвать этот запрос, отправленный в http://www.example.com/query, и доставить результат. Я использовал Jersey в нем, и все отлично работает со спецификациями, за исключением того, что

запросы должны быть эксклюзивными во времени. то есть один запрос должен быть подан в одно мгновение - последующие клики пользователя должны получать сообщение с состоянием HTTP 309, если только сервер не запускает процесс запроса, вызванный моим методом query().

Как достичь этого? Я попытался сделать query() serve @PUT вместо ответов @POST и получил те же результаты.

Может быть, наивный Q по теме. Однако, не очень хорошо знакомы с Restful services.

Я могу сделать это, набирая токен, чтобы контролировать, что за один раз запускается только один запрос, и одновременные запросы получают HTTP 309. Однако для этого на сервере должен быть лучший и простой способ.

Я использую Tomcat 8, Jersey 1.19.

ТИА.

Примечание. Я прочитал PUT vs POST в REST среди других полезных обсуждений.

//=====================

EDIT:

Какой пользователь отправляет запрос, не имеет никакого значения в любое время.

Предположим, что userA отправил запрос. в то время как этот запрос все еще выполняется, то есть перед тем, как query() возвращает ответ на userA, userB отправил запрос. userB должен получать 309 - только потому, что в это время обрабатывается запрос.

Является ли userA= userB или userA < > userB, 309 должен быть возвращен только потому, что есть запрос запроса, когда он уже запущен. и это единственный раз, когда пользователь получает 309.

//============================================= =

РЕДАКТИРОВАТЬ-2:

Я знаю решения w/ concurrency. Я предполагаю, что есть один, использующий функции Restful. это скорее академический Q.

Ответ 1

  • @Koos Gadellaa правильно говорит, что клиент должен блокировать второй запрос до получения ответа. Позвольте мне изложить, почему это самое лучшее. Архитектурно, это относится к проблемам. На сервере нет контекстного понимания того, почему два запроса пришли параллельно. Поэтому он полагается на внеполосное знание, чтобы знать, что параллельные запросы являются плохими. Любое внеполосное знание создает связь, а это означает, что если вы измените, как работает одна часть системы, вы должны изменить другую. Архитектуры RESTful популярны, потому что они уменьшают сцепление. Если один и тот же пользователь регистрируется на двух клиентах, система прерывается. Вы никогда не хотите создавать системы с этим типом взаимодействия клиент-сервер.

  • Что касается ответственности сервера, вступают в игру хорошие методы кодирования, лучше всего будет обеспечить, чтобы службе не мешало несколько параллельных запросов от пользователя. Кэширование может быть вашим другом. На основе параметров запроса ответ может быть записан в файл кэша на диске. Клиент всегда будет перенаправлен с HTTP 303 на URL-адрес кэш файла. 304 Not Modified может использоваться, поэтому клиенту не нужно будет дважды загружать ответ. В этом случае только внеполосное знание - это правильная реализация спецификации HTTP, которая хорошо указана и надежна.

  • Соответствующий код ответа кажется 503, если служба перегружена.

    10.5.4 503 Служба недоступна

    В настоящее время сервер не может обработать запрос из-за временной перегрузки или обслуживания сервера. Подразумевается, что это временное условие, которое будет смягчено после некоторой задержки. Если известно, длина задержки МОЖЕТ указываться в заголовке Retry-After. Если параметр Retry-After не задан, клиент ДОЛЖЕН обрабатывать ответ, как это было бы для ответа 500.

         Note: The existence of the 503 status code does not imply that a
         server must use it when becoming overloaded. Some servers may wish
         to simply refuse the connection.
    
  • Поскольку вы направили меня сюда из моего ответа здесь, вы бы хотели знать правильный подход RESTful. Это будет сложнее, чем решения выше, и я предполагаю, что вы не хотите идти по этому маршруту, но здесь.

    Если серверу необходимо сообщить клиенту, что выполняется запрос, и когда он завершается, необходимо создать ресурсы для этих концепций. Это странно, потому что они существуют в HTTP, и странно переопределять их на более высоком уровне (архитектурный запах).

    • Клиент будет на сервере Request или Query. Этот ресурс будет иметь свойство Response, которое является пустым, и свойство Status, которое пусто. Сервер ответил бы телом, у которого свойство Status установлено на "обработка".
    • Затем клиент будет выполнять GET на этот ресурс (возможно, использовать длительный опрос здесь), чтобы проверить наличие обновлений.
    • Когда ответ был создан, свойство Response будет ссылаться на ресурс ответа или включить встроенный ответ.

    Этот подход связывает то, что происходит с использованием ресурсов. Поэтому только внеполосное знание - это допустимые состояния ресурса.

Ответ 2

Я думаю, вы неправильно сформулировали это. Пользователь, щелкнувший несколько раз, является пользователем, использующим внешний клиент для подключения к вашему серверу. Следовательно, клиент должен обеспечить, чтобы не было нескольких кликов. Javascript может отлично отладить такие запросы.

Сказав это, на ваш запрос: тот факт, что 309 должен быть возвращен. Это проблема concurrency.
Если я правильно прочитал ваши спецификации, это связано с выполняемым запросом базы данных. Рассмотрим следующий код:

result = do_database_thing();
out = make_up_result(result);
return out;

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

boolean locked = get_lock();
if(!locked) return 302;
result = do_database_thing();
release_lock();
out = make_up_result(result);
return out;