2011-03-09 8 views
5

Estoy disfrutando de la negociación automática de contenido HTTP de JAX-RS (específicamente Jersey), es decir, su capacidad para enrutar mis recursos por encabezados "Aceptar" y/o "Tipo de contenido". Pero estoy descubriendo que a veces no me da suficiente control cuando hay un conflicto.Conflictos de negociación de contenido HTTP en JAX-RS/Jersey?

Por ejemplo, considere los siguientes criterios de valoración:

@Path("/order") 
public class OrderController { 

    @GET 
    @Path("{orderID: \\d+}") 
    @Produces("text/html") 
    public View getOrderView(@PathParam("orderID") long id) { 
     Order order = this.getOrderData(id); 
     return new OrderView(order); 
    } 

    @GET 
    @Path("{orderID: \\d+}") 
    @Produces({"application/json", "application/xml"}) 
    public Order getOrderData(@PathParam("orderID") long id) { 
     return new OrderService.findOrder(id); 
    } 
} 

voy a obtener resultados diferentes entre Firefox y Chrome. Firefox se correlacionará con el punto final HTML, mientras que Chrome activará el punto final XML cuando navegue hacia la URL del punto final. La diferencia entre ellos es el orden de los tipos MIME enumerados en sus encabezados Aceptar. Chrome envía el siguiente:

User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_6; en-US) AppleWebKit/534.13 (KHTML, like Gecko) Chrome/9.0.597.107 Safari/534.13 
Accept: application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5 

Versus en Firefox que las listas HTML primera:

User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; en-US; rv:1.9.2.13) Gecko/20101203 Firefox/3.6.13 
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 

parece lógico que se correspondería con la primera entrada cuando todo se ponderan de la misma. Pero en mi caso obtengo los resultados diferentes de los que quiero, por lo que sería bueno determinar un método mejor para desempatar.

Mi pregunta: corta de la inyección de la información de cabecera en estos métodos y realizar el tipo de medio de procesamiento a mí mismo, ¿hay una manera de "ajustar los pesos" por así decirlo, en caso de empate? Por ejemplo, ¿puedo decir que siempre prevalece XML con HTML? Mis clientes RESTful son muy explícitos sobre el tipo que quieren volver, pero los navegadores son notoriamente descuidados con los encabezados Aceptar. (En lo personal creo que deberían ponderar HTML ligeramente por encima de XML ya que esto es lo que esperan los usuarios, pero es un poco tarde para eso.)

Alternativamente, puedo realizar mi propia negociación de contenido personalizado sólo una vez en algún lugar centralizado? No me opongo a escribir esta lógica de forma manual, pero no si eso significa aplicarlo a cada instancia de mis recursos. ¿JAX-RS tiene algún concepto de agregar un filtro a la canalización para modificar las solicitudes antes de que se enruten?

Respuesta

1

Como los Jersey User Guide estados:

Si ambos son igualmente aceptables, entonces el primero se eligió porque se produce primero.

Por lo que sé, esto te deja con dos posibilidades/hacks:

  1. añadir la extensión de archivo para sus URI para anular la cabecera Accept

  2. Escribir un filtro de servlet que sobrescribe el encabezado Aceptar para aquellos Agentes de usuario

+1

Gracias, el filtro de servlet parece funcionar muy bien. Curiosamente, encontré un chico que combina tus dos sugerencias; está escribiendo un filtro de servlet para poder reemplazar la extensión de archivo con un encabezado Accept. Sin embargo, hay un error tipográfico en su código, ya que su comprobación de encabezado distingue entre mayúsculas y minúsculas. Interesante sin embargo: http://www.zienit.nl/blog/2010/01/rest/control-jax-rs-content-negotiation-with-filters – mckamey

+1

Aquí hay un filtro de servlet modificado que agrega soporte para extensiones de archivos y corrige el WebKit Aceptar el orden del encabezado. https://gist.github.com/865216 – mckamey

+0

@mckamey estas adiciones en los comentarios que escribió deben convertirse en una respuesta porque los comentarios no están destinados a sobrevivir para siempre – hiergiltdiestfu

9

Hay un mecanismo en Jersey para anular el grado relativo de preferencia del encabezado HTTP Accept. Simplemente agregue un parámetro "qs" a la anotación @Produces que desea tener prioridad. En su caso: @Produces("text/html;qs=2") Tenga en cuenta que los valores de http "q" oscilan entre 0-1 y los valores de Jersey "qs" deben ser> = 1 (1 es el valor predeterminado).

(he aprendido acerca de esto desde this source, y me escribió una pequeña nota para mí here)

+3

He encontrado que esta solución tiene algunos problemas. Primero, pasa el "; qs = 2" hasta el final en el encabezado Content-Type. Pero el factor decisivo fue que es demasiado pesado. Por ejemplo, jQuery solicita con "Aceptar: application/json, text/javascript, */*; q = 0.01" pero con "text/html; qs = 2" y "application/json", Jersey envía HTML sobre JSON. – mckamey

Cuestiones relacionadas