unsupported resource origin jax javaee enable cross control allow java rest jersey jax-rs cors

java - resource - Cómo manejar CORS usando JAX-RS con Jersey



enable cors java web service (6)

Estoy desarrollando una aplicación cliente Java Script, en el lado del servidor necesito manejar CORS, todos los servicios que había escrito en JAX-RS con JERSEY. Mi código:

@CrossOriginResourceSharing(allowAllOrigins = true) @GET @Path("/readOthersCalendar") @Produces("application/json") public Response readOthersCalendar(String dataJson) throws Exception { //my code. Edited by gimbal2 to fix formatting return Response.status(status).entity(jsonResponse).header("Access-Control-Allow-Origin", "*").build(); }

A partir de ahora, recibo el error No hay encabezado ''Access-Control-Allow-Origin'' presente en el recurso solicitado. Por lo tanto, el origen '' http: // localhost: 8080 '' no tiene acceso permitido ”.

Por favor, ayúdame con esto.

Gracias y Saludos Buda Puneeth


Nota: asegúrese de leer la ACTUALIZACIÓN en la parte inferior

@CrossOriginResourceSharing es una anotación CXF, por lo que no funcionará con Jersey.

Con Jersey, para manejar CORS, normalmente solo uso un ContainerResponseFilter . ContainerResponseFilter para Jersey 1 y 2 son un poco diferentes. Como no ha mencionado qué versión está utilizando, publicaré ambas.

Jersey 2

import java.io.IOException; import javax.ws.rs.container.ContainerRequestContext; import javax.ws.rs.container.ContainerResponseContext; import javax.ws.rs.container.ContainerResponseFilter; @Provider public class CORSFilter implements ContainerResponseFilter { @Override public void filter(ContainerRequestContext request, ContainerResponseContext response) throws IOException { response.getHeaders().add("Access-Control-Allow-Origin", "*"); response.getHeaders().add("Access-Control-Allow-Headers", "origin, content-type, accept, authorization"); response.getHeaders().add("Access-Control-Allow-Credentials", "true"); response.getHeaders().add("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS, HEAD"); } }

Si usa el escaneo de paquetes para descubrir proveedores y recursos, la anotación @Provider debe ocuparse de la configuración por usted. De lo contrario, deberá registrarlo explícitamente en ResourceConfig o en la subclase Application .

Código de muestra para registrar explícitamente el filtro con ResourceConfig :

final ResourceConfig resourceConfig = new ResourceConfig(); resourceConfig.register(new CORSFilter()); final final URI uri = ...; final HttpServer httpServer = GrizzlyHttpServerFactory.createHttpServer(uri, resourceConfig);

Para Jersey 2.x, si tiene problemas para registrar este filtro, aquí hay algunos recursos que podrían ayudarlo

Jersey 1

import com.sun.jersey.spi.container.ContainerRequest; import com.sun.jersey.spi.container.ContainerResponse; import com.sun.jersey.spi.container.ContainerResponseFilter; public class CORSFilter implements ContainerResponseFilter { @Override public ContainerResponse filter(ContainerRequest request, ContainerResponse response) { response.getHttpHeaders().add("Access-Control-Allow-Origin", "*"); response.getHttpHeaders().add("Access-Control-Allow-Headers", "origin, content-type, accept, authorization"); response.getHttpHeaders().add("Access-Control-Allow-Credentials", "true"); response.getHttpHeaders().add("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS, HEAD"); return response; } }

configuración web.xml, puede usar

<init-param> <param-name>com.sun.jersey.spi.container.ContainerResponseFilters</param-name> <param-value>com.yourpackage.CORSFilter</param-value> </init-param>

O ResourceConfig que puedes hacer

resourceConfig.getContainerResponseFilters().add(new CORSFilter());

O escanee paquetes con la anotación @Provider .

EDITAR

Tenga en cuenta que el ejemplo anterior se puede mejorar. Necesitará saber más sobre cómo funciona CORS. Por favor mira here . Por un lado, obtendrá los encabezados de todas las respuestas. Esto puede no ser deseable. Es posible que solo necesite manejar la verificación previa (u OPCIONES). Si desea ver un filtro CORS mejor implementado, puede consultar el código fuente del RESTeasy CorsFilter

ACTUALIZAR

Entonces decidí agregar una implementación más correcta. La implementación anterior es perezosa y agrega todos los encabezados CORS a todas las solicitudes. El otro error es que, dado que es solo un filtro de respuesta , la solicitud aún se procesa. Esto significa que cuando llega la solicitud de verificación previa, que es una solicitud de OPTIONS, no se implementará ningún método OPTIONS, por lo que obtendremos una respuesta 405, que es incorrecta.

Así es como debería funcionar. Por lo tanto, hay dos tipos de solicitudes CORS: solicitudes simples y solicitudes de verificación previa . Para una solicitud simple, el navegador enviará la solicitud real y agregará el encabezado de solicitud de Origin . El navegador espera que la respuesta tenga el encabezado Access-Control-Allow-Origin y dice que el origen del encabezado Origin está permitido. Para que se considere una "solicitud simple", debe cumplir con los siguientes criterios:

  • Sé uno de los siguientes métodos:
    • OBTENER
    • CABEZA
    • ENVIAR
  • Además de los encabezados configurados automáticamente por el navegador, la solicitud solo puede contener los siguientes encabezados configurados manualmente :
    • Accept
    • Accept-Language
    • Content-Language
    • Content-Type
    • DPR
    • Save-Data
    • Viewport-Width
    • Width
  • Los únicos valores permitidos para el encabezado Content-Type son:
    • application/x-www-form-urlencoded
    • multipart/form-data
    • text/plain

Si la solicitud no cumple con todos estos tres criterios, se realiza una solicitud Preflight. Esta es una solicitud de OPCIONES que se realiza al servidor, antes de que se realice la solicitud real. Contendrá diferentes encabezados Access-Control-XX-XX , y el servidor debe responder a esos encabezados con sus propios encabezados de respuesta CORS. Aquí están los encabezados coincidentes:

Preflight Request and Response Headers +-----------------------------------+--------------------------------------+ | REQUEST HEADER | RESPONSE HEADER | +===================================+======================================+ | Origin | Access-Control-Allow-Origin | +-----------------------------------+--------------------------------------+ | Access-Control-Request-Headers | Access-Control-Allow-Headers | +-----------------------------------+--------------------------------------+ | Access-Control-Request-Method | Access-Control-Allow-Methods | +-----------------------------------+--------------------------------------+ | XHR.withCredentials | Access-Control-Allow-Credentials | +-----------------------------------+--------------------------------------+

  • Con el encabezado de solicitud de Origin , el valor será el dominio del servidor de origen, y la respuesta Access-Control-Allow-Header debe ser esta misma dirección o * para especificar que todos los orígenes están permitidos.

  • Si el cliente intenta configurar manualmente los encabezados que no están en la lista anterior, entonces el navegador establecerá el Access-Control-Request-Headers , con el valor de ser una lista de todos los encabezados que el cliente está tratando de configurar. El servidor debe responder con un Access-Control-Allow-Headers respuesta Access-Control-Allow-Headers , siendo el valor una lista de encabezados que permite.

  • El navegador también establecerá el encabezado de solicitud Access-Control-Request-Method , siendo el valor el método HTTP de la solicitud. El servidor debe responder con el encabezado de respuesta Access-Control-Allow-Methods , siendo el valor una lista de los métodos que permite.

  • Si el cliente usa XHR.withCredentials , entonces el servidor debe responder con el encabezado de respuesta Access-Control-Allow-Credentials , con un valor true . Lee más aquí .

Entonces, con todo lo dicho, aquí hay una mejor implementación. Aunque esto es mejor que la implementación anterior, sigue siendo inferior al RESTEasy al que me vinculé , ya que esta implementación aún permite todos los orígenes. Pero este filtro cumple mejor las especificaciones CORS que el filtro anterior, que solo agrega los encabezados de respuesta CORS a todas las solicitudes. Tenga en cuenta que también es posible que deba modificar el Access-Control-Allow-Headers para que coincida con los encabezados que permitirá su aplicación; es posible que desee agregar o eliminar algunos encabezados de la lista en este ejemplo.

@Provider @PreMatching public class CorsFilter implements ContainerRequestFilter, ContainerResponseFilter { /** * Method for ContainerRequestFilter. */ @Override public void filter(ContainerRequestContext request) throws IOException { // If it''s a preflight request, we abort the request with // a 200 status, and the CORS headers are added in the // response filter method below. if (isPreflightRequest(request)) { request.abortWith(Response.ok().build()); return; } } /** * A preflight request is an OPTIONS request * with an Origin header. */ private static boolean isPreflightRequest(ContainerRequestContext request) { return request.getHeaderString("Origin") != null && request.getMethod().equalsIgnoreCase("OPTIONS"); } /** * Method for ContainerResponseFilter. */ @Override public void filter(ContainerRequestContext request, ContainerResponseContext response) throws IOException { // if there is no Origin header, then it is not a // cross origin request. We don''t do anything. if (request.getHeaderString("Origin") == null) { return; } // If it is a preflight request, then we add all // the CORS headers here. if (isPreflightRequest(request)) { response.getHeaders().add("Access-Control-Allow-Credentials", "true"); response.getHeaders().add("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS, HEAD"); response.getHeaders().add("Access-Control-Allow-Headers", // Whatever other non-standard/safe headers (see list above) // you want the client to be able to send to the server, // put it in this list. And remove the ones you don''t want. "X-Requested-With, Authorization, " + "Accept-Version, Content-MD5, CSRF-Token"); } // Cross origin requests can be either simple requests // or preflight request. We need to add this header // to both type of requests. Only preflight requests // need the previously added headers. response.getHeaders().add("Access-Control-Allow-Origin", "*"); } }

Para obtener más información sobre CORS, sugiero leer los documentos de MDN sobre here


Con JAX-RS , simplemente puede agregar la anotación @CrossOrigin(origin = yourURL) a su controlador de recursos. En su caso, sería @CrossOrigin(origin = "http://localhost:8080") pero también podría usar @CrossOrigin(origin = "*") para permitir que cualquier solicitud pase por su servicio web.
Puede consultar THIS para obtener más información.


Eliminar la anotación " @CrossOriginResourceSharing(allowAllOrigins = true) "

Luego, responda la respuesta como a continuación:

return Response.ok() .entity(jsonResponse) .header("Access-Control-Allow-Origin", "*") .build();

¡Pero el jsonResponse debería reemplazarse con un objeto POJO!


La otra respuesta puede ser estrictamente correcta, pero engañosa. La parte que falta es que puedes mezclar filtros de diferentes fuentes. Aunque pensé que Jersey podría no proporcionar el filtro CORS (no es un hecho que verifiqué, pero confío en la otra respuesta al respecto), puede usar el filtro CORS de tomcat .

Lo estoy usando con éxito con Jersey. Tengo mi propia implementación del filtro de autenticación básica, por ejemplo, junto con CORS. Lo mejor de todo es que el filtro CORS está configurado en XML web, no en código.


La respuesta de peeskillet es correcta. Pero recibo este error cuando actualizo la página web (solo funciona en la primera carga):

The ''Access-Control-Allow-Origin'' header contains multiple values ''*, *'', but only one is allowed. Origin ''http://127.0.0.1:8080'' is therefore not allowed access.

Entonces, en lugar de usar el método add para agregar encabezados para la respuesta, uso el método put. Esta es mi clase

public class MCORSFilter implements ContainerResponseFilter { public static final String ACCESS_CONTROL_ALLOW_ORIGIN = "Access-Control-Allow-Origin"; public static final String ACCESS_CONTROL_ALLOW_ORIGIN_VALUE = "*"; private static final String ACCESS_CONTROL_ALLOW_CREDENTIALS = "Access-Control-Allow-Credentials"; private static final String ACCESS_CONTROL_ALLOW_CREDENTIALS_VALUE = "true"; public static final String ACCESS_CONTROL_ALLOW_HEADERS = "Access-Control-Allow-Headers"; public static final String ACCESS_CONTROL_ALLOW_HEADERS_VALUE = "Cache-Control, Pragma, Origin, Authorization, Content-Type, X-Requested-With, Accept"; public static final String ACCESS_CONTROL_ALLOW_METHODS = "Access-Control-Allow-Methods"; public static final String ACCESS_CONTROL_ALLOW_METHODS_VALUE = "GET, POST, PUT, DELETE, OPTIONS, HEAD"; public static final String[] ALL_HEADERs = { ACCESS_CONTROL_ALLOW_ORIGIN, ACCESS_CONTROL_ALLOW_CREDENTIALS, ACCESS_CONTROL_ALLOW_HEADERS, ACCESS_CONTROL_ALLOW_METHODS }; public static final String[] ALL_HEADER_VALUEs = { ACCESS_CONTROL_ALLOW_ORIGIN_VALUE, ACCESS_CONTROL_ALLOW_CREDENTIALS_VALUE, ACCESS_CONTROL_ALLOW_HEADERS_VALUE, ACCESS_CONTROL_ALLOW_METHODS_VALUE }; @Override public ContainerResponse filter(ContainerRequest request, ContainerResponse response) { for (int i = 0; i < ALL_HEADERs.length; i++) { ArrayList<Object> value = new ArrayList<>(); value.add(ALL_HEADER_VALUEs[i]); response.getHttpHeaders().put(ALL_HEADERs[i], value); //using put method } return response; } }

Y agregue esta clase a init-param en web.xml

<init-param> <param-name>com.sun.jersey.spi.container.ContainerResponseFilters</param-name> <param-value>com.yourpackage.MCORSFilter</param-value> </init-param>


Para resolver esto para mi proyecto, utilicé respuesta y llegué a esto:

<plugin> <groupId>org.apache.tomcat.maven</groupId> <artifactId>tomcat7-maven-plugin</artifactId> <version>2.2</version> <executions> <execution> <id>run-embedded</id> <goals> <goal>run</goal> </goals> <phase>pre-integration-test</phase> <configuration> <port>${maven.tomcat.port}</port> <useSeparateTomcatClassLoader>true</useSeparateTomcatClassLoader> <contextFile>${project.basedir}/tomcat/context.xml</contextFile> <!--enable CORS for development purposes only. The web.xml file specified is a copy of the auto generated web.xml with the additional CORS filter added --> <tomcatWebXml>${maven.tomcat.web-xml.file}</tomcatWebXml> </configuration> </execution> </executions> </plugin>

El filtro CORS es el filtro de ejemplo básico del sitio tomcat.

Editar :
La variable maven.tomcat.web-xml.file es una propiedad definida por pom para el proyecto y contiene la ruta al archivo web.xml (ubicado dentro de mi proyecto)