jax - Spring-Resteasy-Cabecera de Cors Double Access-Control-Allow-Origin en respuesta
java restful cross domain (4)
Configuré una aplicación web con Spring 3 y Resteasy; dado que mis recursos requieren autenticación, no estoy autorizado a utilizar * como Access-Control-Allow-Origin. Así que configuré
org.jboss.resteasy.plugins.interceptors.CorsFilter
con el dominio de origen correcto. Esto funciona con un cliente de escritorio (Paw para Mac OS y otros), pero no con el navegador (Chrome); el problema es que la respuesta contiene un doble valor para Access-Control-Allow-Origin, que es el que he configurado y ''*''.
CorsFilter no tiene la culpa porque, incluso si configuras más de un origen, siempre pone solo un valor para el encabezado, el que solicitó la solicitud.
Simplemente no tengo idea de quién está poniendo ese encabezado extra (y erróneo), ¿alguna idea sobre dónde podría buscar? Tenga en cuenta que el encabezado doble se produce en las solicitudes GET, pero no en las solicitudes de OPCIONES.
Finalmente descubrí que hay un MessageBodyWriterInterceptor patentado en el classpath que hace un encabezado add incorrecto; ahora depende de mí eliminar eso. Una cosa que aprendí es que si algo sucede solo cuando hay un cuerpo para escribir, un buen punto de partida es sin duda la tubería de renderizado
No estoy seguro de dónde proviene su doble encabezado, pero ¿intentó utilizar un filtro personalizado? p.ej :
@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class SimpleCorsFilter implements Filter {
public SimpleCorsFilter() {
}
@Override
public void doFilter(ServletRequest req,
ServletResponse res,
FilterChain chain) throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) res;
HttpServletRequest request = (HttpServletRequest) req;
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE, PUT");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "X-Requested-With, Authorization, Content-Type");
if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {
response.setStatus(HttpServletResponse.SC_OK);
} else {
chain.doFilter(req, res);
}
}
@Override
public void init(FilterConfig filterConfig) {
}
@Override
public void destroy() {
}
}
Intenté las siguientes acciones y funcionó como un encanto:
Primero, registre la clase de proveedor CorsFilter en su web.xml:
<context-param>
<param-name>resteasy.providers</param-name>
<param-value>org.jboss.resteasy.plugins.interceptors.CorsFilter</param-value>
</context-param>
Al hacerlo, su servidor ya está habilitado para manejar las solicitudes CORS, sin embargo, debe agregar algunos orígenes permitidos para que funcione, por lo tanto, debe tener acceso a la instancia de CorsFilter, que fue creada por RestEasy y luego agregar todas las URL que desea otorgar acceso o agregar un * si desea otorgar acceso a alguno.
En este sentido, si está utilizando la integración de RestEasy Spring, necesitará obtener una instancia de la clase org.jboss.resteasy.spi.ResteasyProviderFactory
al conectarla automáticamente a su código:
@Autowired
private ResteasyProviderFactory processor;
luego use un método de configuración anotado con @PostConstruct
para obtener la instancia de CorsFilter de ResteasyProviderFactory
como el siguiente fragmento de código:
@PostConstruct
public void setUp() {
ContainerRequestFilter[] requestFilters = processor.getContainerRequestFilterRegistry().preMatch();
CorsFilter filter = (CorsFilter) Iterables.getLast(Iterables.filter(Arrays.asList(requestFilters), Predicates.instanceOf(CorsFilter.class)));
filter.getAllowedOrigins().add("*");
}
PD: estoy usando este marco:
- Spring Framework 3.2.18.RELEASE
- RestEasy 3.0.12.Final
¡Espero que ayude!
Para aquellos que luchan como yo, que no usan el inicio de la aplicación, sino solo Spring + Reasteasy.
Solo agregue en web.xml:
<context-param>
<param-name>resteasy.providers</param-name>
<param-value>package.to.your.cors.CORSFilter</param-value>
</context-param>
Y crea la clase CORSFilter de Java como
package package.to.your.cors;
import java.io.IOException;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerResponseContext;
import javax.ws.rs.container.ContainerResponseFilter;
import javax.ws.rs.ext.Provider;
@Provider
public class CORSFilter implements ContainerResponseFilter {
@Override
public void filter(final ContainerRequestContext requestContext,
final ContainerResponseContext cres) throws IOException {
cres.getHeaders().add("Access-Control-Allow-Origin", "*");
cres.getHeaders().add("Access-Control-Allow-Methods", "POST, GET, PUT, OPTIONS, DELETE");
cres.getHeaders().add("Access-Control-Allow-Headers", "X-Auth-Token, Content-Type");
cres.getHeaders().add("Access-Control-Max-Age", "4800");
}
}
Funciona a las mil maravillas.
PD: inspirado por la respuesta de s_bighead, pero no pude comentar su respuesta para agregar mis detalles.