2009-04-12 12 views
14

He pasado mucho tiempo leyendo recientemente la especificación HTTP 1.1 y relacionándola con REST. He encontrado que hay dos interpretaciones del método HTTP DELETE con respecto a su "idempotencia" y seguridad. Estos son los dos campos:¿Cuál es la forma correcta de ver idempotencia en términos de HTTP DELETE?

  1. Si elimina un recurso con DELETE HTTP, y tiene éxito (200 OK), y luego intenta eliminar esa cantidad de recursos N de veces, usted debe volver un mensaje de éxito (200 OK) para todas y cada una de esas llamadas de eliminación. Esta es su "idempotencia".

  2. Si elimina un recurso con HTTP DELETE, y lo logra (200 OK), y luego intenta eliminar ese recurso nuevamente, debe recuperar un mensaje de error (410 Gone) porque se eliminó el recurso.

La especificación dice BORRAR es idempotente, claro, pero también dice que las secuencias de eventos idempotent todavía pueden producir efectos secundarios. Realmente siento que el segundo campamento es correcto, y el primero es engañoso. ¿Qué "seguridad" hemos introducido al permitir que los clientes piensen que fueron la causa de la eliminación de un recurso previamente eliminado?

Hay un montón de personas en el primer campamento, entre ellas varios autores sobre el tema, por lo que quería comprobar si había alguna razón de peso además de las emociones que llevan a las personas al primer campamento.

+0

Con su # 2, creo que debería sacar "recientemente" la reciente eliminación no debería tener nada que ver con la estrategia de esta respuesta. –

+0

@JeffMartin Tienes razón, fue más conversacional que real. Remoto. –

Respuesta

19

Ser idempotente no significa que una solicitud no puede tener efectos secundarios (eso es lo que describe la propiedad 'segura'). Simplemente significa que emitir la misma solicitud varias veces no dará lugar a efectos secundarios diferentes o adicionales.

En mi opinión, la solicitud DELETE posterior debería devolver un error; sigue siendo idempotente porque el estado del servidor es el mismo que si solo se hubiera realizado una solicitud DELETE. Entonces, devolver nuevamente el estado de 200 OK también debería estar bien - No creo que ser idempotente requiera la devolución de un código de error para las siguientes solicitudes DELETE - es solo que devolver el estado del error parece tener más sentido para mí.

+0

Tengo la misma opinión, me alegro de que alguien más la comparta. Supongo que solo necesitaba escucharlo. Gracias. Tengo bastantes libros sobre el tema y un número sorprendente trata la idempotencia como si también fuera segura, y no lo es. –

+0

Una advertencia: Apenas me llamaría un experto en HTTP/REST ... –

+0

Como punto de vista opuesto, siento que una solicitud DELETE es más parecida a "Asegúrese de que este recurso se elimine/elimine". Si realmente existe en el momento de la solicitud realmente no importa el estado de éxito de la respuesta. Si dos clientes diferentes envían la solicitud DELETE "al mismo tiempo", ¿por qué uno debería obtener una respuesta de error y el otro éxito, cuando en efecto ambos llevaron a cabo con éxito el objetivo? –

2

@MichaelBurr tiene razón acerca de la idempotencia y los efectos secundarios.

Mi opinión es que hay 2 estados involucrados en una determinada solicitud REST, el estado del cliente y el estado del servidor. REST tiene que ver con la transferencia de estos estados entre el servidor y el cliente, de modo que el estado del cliente se correlaciona con un subconjunto del estado del servidor, en otras palabras, el subconjunto se mantiene coherente con el servidor. Debido a esa idempotencia, esto debería significar que las solicitudes idempotentes subsiguientes no darán como resultado que ninguno de los dos estados sea diferente de lo que sería hacerlo solo una vez. Con el primer DELETE, imagina que el servidor borra el recurso y le informa al cliente que también puede eliminar el recurso (ya que el recurso "ya no existe"). Ahora ambos estados deberían ser idénticos a before con menos el elemento que se eliminó. Para que el cliente haga algo diferente cuando intenta eliminar el elemento una vez que ya ha sido eliminado, el estado que se transfiere del servidor al cliente debe contener información diferente. El servidor puede hacer las cosas de forma ligeramente diferente con la información de que el recurso ya fue eliminado, pero una vez que responde con algo diferente, la idempotencia de los métodos está esencialmente rota.

Para la función idempotente:

delete(client_state) -> client_state - {item} 
delete(delete(client_state)) -> client_state - {item} 
delete(client_state) = delete(delete(client_state)) 

La mejor manera de garantizar este idempotencia es si la respuesta del servidor es idéntico, eso significa que la única manera de que el estado del cliente para romper el idempotencia es para que haya no determinación o efectos secundarios en el manejo de la respuesta por parte del cliente (lo que probablemente apunta a una implementación incorrecta del manejo de la respuesta).

Si existe un acuerdo entre el cliente y el servidor de que los códigos de estado existen fuera de la representación del estado que se transfiere (REST), es posible informar al cliente que el elemento "ya no existe" (como lo haría en la primera solicitud) con el comentario adicional de que se había eliminado previamente. Lo que el cliente hace con esta información no está claro, pero no debería afectar el estado del cliente resultante. Pero entonces el código de estado no se puede usar para comunicar el estado, o más bien si también comunica el estado en otras situaciones (como quizás "no tienes permiso para eliminar este elemento" o "el elemento no se eliminó"), luego hay alguna ambigüedad o confusión introducida. Por lo tanto, al menos necesita una buena razón para introducir más confusión en la comunicación si quiere decir que DELETE es idempotente y aún tienen la respuesta del servidor depende de las solicitudes DELETE anteriores que son idénticas.

peticiones HTTP implican eliminar métodos, por lo que la función podría parecerse

delete(client_state) = send_delete(client_state) -> receive_delete(client_state) 
               -> respond_to_delete(informative_state) 
               -> handle_response(informative_state) 
               -> client_state - {item} 
+0

Este es un argumento interesante. Todavía no tengo claro cómo "OK" resuelve esta incoherencia o ambigüedad forzada. Estoy de acuerdo en que si proporcionas una respuesta idéntica, estás mejor, pero no creo que rompamos las transiciones de estado si elegimos desambiguar "este recurso nunca existió en primer lugar, por lo que no puedes eliminarlo" (404) vs. "este recurso solía estar aquí, pero ya no está, entonces probablemente debería vaciar su caché" (406) ... –

+1

... Obtendría respuestas idénticas del servidor en cada situación donde esto fue cierto para un recurso específico durante su vida. Solicitar la identidad a través de OK es pedir al servidor que oculte detalles sobre lo que ocurrió antes/después de que un cliente responda, lo que puede no ser un buen diseño según la API. Lo voy a masticar más, pero aún me gusta ELIMINAR 1 -> OK, ELIMINAR 2..n - DESAPARECIÓ por un recurso que alguna vez se creó y ELIMINAR 1..n 404 NO ENCONTRADO para todo lo demás. –

+0

@DanielCrenna pero intenta eliminar algo significa que cree que existe (es decir, el cliente supone que debe estar en el servidor). Para recursos nunca creados 404 es el código más apropiado para la operación GET. – tenkod

0

Wikipedia define idempotencia como una operación que:

se puede aplicar varias veces sin cambiar el resultado más allá de la aplicación inicial.

Tenga en cuenta que hablan sobre el result de la operación. Para mí, esto incluye ambos el estado del servidor y el código de respuesta.

La especificación HTTP es un poco más vaga al respecto. Es defines it especifica que los métodos HTTP son Idempotentes:

si el efecto deseado de varias solicitudes idénticas es el mismo que para una sola solicitud.

Si usted interpreta como effectresult en la definición de Wikipedia entonces ellos significan lo mismo. En cualquier caso, cuestiono el beneficio práctico de decirle a los clientes que el recurso ya se ha eliminado.

Punto final: Idempotence se define en términos de un único cliente. Una vez que comience a presentar solicitudes simultáneas de otros clientes, todas las apuestas están desactivadas. Se supone que debes utilizar encabezados de actualización condicional (como If-Match-ETag) para tratar estos casos.

Para reiterar: debe devolver el mismo código de retorno, si el recurso acaba de ser eliminado, fue eliminado por una solicitud anterior, o nunca existió en absoluto.

+0

No, su "efecto" no está destinado a cubrir la respuesta también. Lo que usted propone es que DELETE siempre debe pasar ("200") o fallar ("404" o "410"), sin importar el estado del servidor. Esto no tiene ningún sentido y, además, no ayuda al cliente en absoluto. –

+0

@JulianReschke, si lees http://tools.ietf.org/html/draft-ietf-httpbis-p2-semantics-24#section-4.3.5 la especificación enumera todas las respuestas legales a 'DELETE'. '404' y' 410' no son uno de ellos. Como tal, elimine el voto abajo. – Gili

+0

no, la especificación * no * enumera "todas" las respuestas legales para ELIMINAR. Simplemente da ejemplos. –

Cuestiones relacionadas