2010-09-01 13 views
10

Estoy implementando un servicio web RESTful que accede a una base de datos. Las entidades en la base de datos están versionadas para detectar múltiples actualizaciones. Por ejemplo, si el valor actual es {"name":"Bill", "comment":"tinker", "version":3}, si un usuario PONE {"name":"Bill", "comment":"tailor", "version":3}, la solicitud tendrá éxito (200 OK) y el nuevo valor será {"name":"Bill", "comment":"tailor", "version":4}. Si un segundo usuario PONE {"name":"Bill", "comment":"sailor", "version":3"}, esa solicitud fallará (409 Conflicto) porque el número de versión no coincide.HTTP Status 412 (Precondition Failed) y Database Versioning

Existen interfaces no RESTful existentes, por lo que el diseño de las bases de datos no se puede cambiar. La interfaz RESTful llama a una interfaz existente que maneja los detalles de la comprobación de la versión.

Una regla de oro en los servicios web RESTful es seguir los detalles de HTTP siempre que sea posible. ¿Sería mejor en este caso usar un encabezado condicional en la solicitud y devolver el 412 Condición previa fallida si la versión no coincide? El encabezado apropiado parece ser If-Match. Este encabezado toma un ETag (etiqueta de entidad) que podría ser un hash de la representación del estado actual del recurso.

Si lo hiciera, los ETags serían por apariencia, porque la versión seguiría siendo la prueba real para la que estoy probando.

¿Hay alguna razón por la que debería hacer esto, aparte de "hacerlo más RESTANTE", sea lo que sea que se supone que significa?

Respuesta

17

Lo apropiado es seguir siempre las especificaciones HTTP si usa HTTP, y la razón es simplemente permitir que las personas que entienden la especificación funcionen correctamente.

412 deberían utilizarse sólo si una condición previa (por ejemplo, If-Match) causó la coincidencia de la versión a fallar, mientras que 409 debe usarse si la entidad causaría un conflicto (la especificación HTTP en sí alude a este comportamiento en el definition of 409).

Por lo tanto, un cliente que no envía ETags no se espera un 412. Por el contrario, un cliente que hace enviar ETags no va a entender que es ETags que están causando un 409.

que se pegaba de una manera. Usted dice que "el esquema de la base de datos no puede cambiar", pero eso no lo detiene (directamente en la capa del servidor HTTP) para extraer la versión de la representación de la base de datos y colocarla en el ETag, y luego en el camino de entrada, tome el encabezado If-Match y vuelva a colocarlo en el campo de versión.

Pero hacerlo completamente en el cuerpo de la entidad no está prohibido. Solo requiere que expliques el concepto y cómo funciona, mientras que con la solución ETag puedes simplemente indicar a las personas las especificaciones HTTP.

Edit: Y la bandera de versión no tiene que ser un hash del recurso actual; una versión es bastante aceptable. ETag: "3" es un ETag perfectamente válido.

+0

tiene alguna pista sobre mi problema: http://stackoverflow.com/questions/19009312/how-to-detect-412-precondition-failed-errors-in-android-webview-url –

+1

"* La versión flag no tiene que ser un hash del recurso actual * "- lo hace si desea mitigar el riesgo de que los usuarios adivinen cuál es la versión esperada y eludiendo la comprobación de concurrencia. – James

+1

Heh :-) Realmente no digo que {{ETag: "3"}} sea una buena idea ... Hacerlo opaco generalmente es una buena idea, aunque reduce la visibilidad. Considere {{ETag: "3: eccbc8"}} - donde "eccbc8 son los primeros 6 caracteres del md5sum del carácter" 3 ".Esto obliga al cliente a usar etiquetas de entidad de la manera en que están destinadas; pero mantiene la visibilidad (el "3" está ahí para que los humanos puedan interpretar esto como "versión 3"). Todavía no estamos procesando el contenido real. – mogsie