java - trata - video viral de la moto
¿Cómo ignorar los clics múltiples de un usuario impaciente? (2)
Tengo una consulta para responder a la solicitud estándar de clientes remotos. Estándar en el sentido de que no requiere parámetros desde fuera del servidor. Cada vez que alguien envía una solicitud a una URL, digamos http://www.example.com/query , obtiene el contenido de un reply.xml
en el cuerpo de la respuesta, según lo que la base de datos entregue en ese momento. El contenido de reply.xml
solo cambia en los contenidos de la base de datos en el servidor, y no cambia en nada externo como quién hace la consulta, en qué entrada, etc., por lo tanto no toma params de los clientes. Ni siquiera estoy verificando ninguna autenticación, estamos dejando todo al firewall.
Así que escribí un método @POST
, digamos query()
para invocarlo en una solicitud publicada en http://www.example.com/query , y entregar el resultado. Utilicé Jersey
en él y todo está funcionando bien para las especificaciones, excepto que
las solicitudes deben ser exclusivas a través del tiempo. es decir, una solicitud debe enviarse a la vez; los clics de usuario posteriores deben recibir un mensaje con el estado HTTP 309 a menos que el servidor no esté ejecutando un proceso de consulta invocado por mi método query()
.
¿Cómo lograr esto? Intenté hacer que query()
sirviera @PUT
lugar de respuestas @POST
, y obtuve los mismos resultados.
Tal vez una Q ingenua sobre el tema. Sin embargo, no estoy muy familiarizado con los servicios de Restful.
Puedo hacerlo enhebrando un token para controlar que solo se ejecute una consulta a la vez y hacer que las solicitudes simultáneas reciban el HTTP 309. Sin embargo, debe haber una forma mejor y más fácil de lograr esto en el servidor.
Estoy usando Tomcat 8, Jersey 1.19.
TIA.
Nota: He leído PUT vs POST en REST, entre otras discusiones útiles.
// =====================
EDITAR:
El usuario que envía el quer no hace ninguna diferencia en ningún momento.
Supongamos que el userA
envió una consulta. mientras la consulta aún se está ejecutando, es decir, antes de que query()
devuelva la respuesta a userA
, userB
envió una consulta. userB
debería obtener un 309-- solo porque se está procesando una consulta en ese momento.
Ya sea que userA
= userB
o userA
<> userB
sea inmaterial aquí, se debe devolver un 309 solo porque hay una solicitud de consulta mientras una ya se está ejecutando. y esa es la única vez que un usuario obtiene un 309.
// ===========================================
EDIT-2:
Soy consciente de las soluciones con control de concurrencia. Supongo que hay uno que usa las características de Restful. esto es más bien una Q académica.
Creo que estás encuadrándolo mal. Un usuario que hace clic varias veces es un usuario que usa el cliente frontend para conectarse a su servidor. Por lo tanto, depende del cliente asegurarse de que no se produzcan clics múltiples. Javascript puede defenderse perfectamente de tales solicitudes.
Habiendo dicho eso, a su pedido: el hecho de que un 309 debe ser devuelto. Este es un problema de concurrencia.
Si leo sus especificaciones correctamente, está relacionado con una consulta de base de datos que se está realizando. Considera el siguiente código:
result = do_database_thing();
out = make_up_result(result);
return out;
Según estas especificaciones, la única solicitud es que la sección crítica esté en do_database_thing. Si make_up_results es lento, se permiten varias solicitudes. Entonces la solución natural es usar el bloqueo en la base de datos. Si debe abarcar todo el método query () (es decir, no la consulta de la base de datos en sí misma ), solicite el bloqueo anticipadamente y suelte el bloqueo al final. Entonces el código se convierte en:
boolean locked = get_lock();
if(!locked) return 302;
result = do_database_thing();
release_lock();
out = make_up_result(result);
return out;
@Koos Gadellaa tiene razón al decir que el cliente debería bloquear la segunda solicitud hasta que llegue la respuesta. Permítanme exponer por qué esto es lo mejor que se puede hacer. Arquitectónicamente , se relaciona con preocupaciones. El servidor no tiene conocimiento de contexto sobre por qué dos solicitudes han llegado en paralelo. Por lo tanto, confía en el conocimiento fuera de banda para saber que las solicitudes paralelas son malas. Cualquier conocimiento fuera de banda crea un acoplamiento, lo que significa que si cambia la forma en que funciona una parte del sistema, debe cambiar la otra. Las arquitecturas RESTful son populares porque reducen el acoplamiento. Si el mismo usuario inicia sesión en dos clientes, el sistema se rompe. Nunca desea construir sistemas con este tipo de acoplamiento cliente-servidor.
En cuanto a la responsabilidad del servidor, las buenas prácticas de codificación entran en juego, lo mejor que se puede hacer es garantizar que el servicio no se vea obstaculizado por múltiples solicitudes paralelas del usuario. El almacenamiento en caché puede ser tu amigo. En función de los parámetros de consulta, la respuesta podría escribirse en un archivo de caché en el disco. El cliente siempre se redirigiría con HTTP 303 a la URL del archivo de caché. 304 Not Modified podría utilizarse para que el cliente no tenga que descargar la respuesta dos veces. En este escenario, el único conocimiento fuera de banda es la implementación adecuada de la especificación HTTP que está bien especificada y es robusta.
El código de respuesta apropiado parece ser 503 si el servicio está sobrecargado.
10.5.4 Servicio 503 no disponible
El servidor actualmente no puede manejar la solicitud debido a una sobrecarga temporal o mantenimiento del servidor. La implicación es que esta es una condición temporal que se aliviará después de un poco de retraso. Si se conoce, la duración de la demora PUEDE indicarse en un encabezado Retry-After. Si no se da Reintentar-Después, el cliente DEBERÍA manejar la respuesta como lo haría con una respuesta de 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.
Como me ha dirigido aquí desde mi respuesta aquí , parece que desea conocer el enfoque RESTful correcto. Esto será más complejo que las soluciones anteriores y supongo que no desea tomar esta ruta, pero aquí está.
Si el servidor necesita comunicar al cliente que se está realizando una solicitud y cuándo se completa, entonces se deben crear recursos para esos conceptos . Esto se siente extraño porque existen conceptos en HTTP y es extraño reimplementarlos en un nivel superior (olor arquitectónico).
- El cliente POSTARÍA un recurso
Request
oQuery
al servidor. Este recurso tendría una propiedad deResponse
que está vacía y una propiedad deStatus
que está vacía. El servidor respondería con un cuerpo que tiene la propiedad deStatus
establecida en "procesamiento". - Luego, el cliente realizaría GET en este recurso (posiblemente use sondeos largos aquí) para buscar actualizaciones.
- Cuando se haya creado la
Response
, la propiedad deResponse
se vinculará a un recurso de respuesta o se incrustará la respuesta.
Este enfoque comunica lo que está pasando con los recursos. Por lo tanto, el único conocimiento fuera de banda son los estados válidos del recurso .
- El cliente POSTARÍA un recurso