Как игнорировать несколько кликов от нетерпеливого пользователя?
У меня есть запрос для ответа на стандартный запрос удаленных клиентов. Стандарт в том смысле, что он не принимает никаких параметров извне сервера. Всякий раз, когда
любой отправляет запрос на 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;