Foros del Web » Programación para mayores de 30 ;) » Java »

Error con CORS en API REST

Estas en el tema de Error con CORS en API REST en el foro de Java en Foros del Web. Hola, tengo un servicio rest que funciona bien con el postman pero me da un error al ser consumido en el navegador Código: @POST //@Consumes("application/x-www-form-urlencoded") ...
  #1 (permalink)  
Antiguo 13/12/2019, 13:34
Avatar de Hyemin  
Fecha de Ingreso: agosto-2014
Mensajes: 147
Antigüedad: 10 años, 3 meses
Puntos: 0
Error con CORS en API REST

Hola, tengo un servicio rest que funciona bien con el postman pero me da un error al ser consumido en el navegador

Código:
  @POST
    //@Consumes("application/x-www-form-urlencoded")
    @Produces(MediaType.APPLICATION_JSON)
    public Response login(@HeaderParam("usuario") String usuario,
            @HeaderParam("pass") String pass) {

        Usuario u = new Usuario();

        
        LdapService ld = new LdapService();
        LdapUser usuarioActual = new LdapUser();
        try {
            usuarioActual = ld.validarUsuario(usuario, pass);
        } catch (LDAPException ex) {
            Logger.getLogger(LoginResource.class.getName()).log(Level.SEVERE, null, ex);
        }
        
        u.usuario = usuarioActual.getNombre();
        u.rol = usuarioActual.getRol();

       return Response
      .status(Response.Status.OK)
      .header("Access-Control-Allow-Origin", "*")
      .header("Access-Control-Allow-Credentials", "true")
      .header("Access-Control-Allow-Headers: 'application/json'",
        "origin, content-type, accept, authorization")
      .header("Access-Control-Allow-Methods", 
        "GET, POST, PUT, DELETE, OPTIONS, HEAD")
      .entity(u)
      .build();
        
    }
Este metodo en el postman me devuelve un JSON correcto

Ahora, en Angular cuando lo consumo me sale este error en el navegador
Código:
zone-evergreen.js:2952 Cross-Origin Read Blocking (CORB) blocked cross-origin response http://192.168.1.7:8080/rest2/webresources/login with MIME type application/vnd.sun.wadl+xml. See https://www.chromestatus.com/feature/5629709824032768 for more details.
Probe pila de cosas y no logro hacerlo andar, me falta algo en mi codigo de java?
  #2 (permalink)  
Antiguo 13/12/2019, 14:41
 
Fecha de Ingreso: abril-2011
Mensajes: 170
Antigüedad: 13 años, 7 meses
Puntos: 68
Respuesta: Error con CORS en API REST

Pues entonces el problema está en el cliente, o sea en cómo realizas la petición con JavaScript.

Según lo que he leído de ese error, posiblemente se deba a que el navegador no espera recibir contenido application/vnd.sun.wadl+xml del servidor porque en la cabecera Accept de la petición has indicado otra cosa distinta (ej. application/xml).

Te recomiendo mostrar el código JavaScript que hace la petición para que podamos localizar el problema.

Un saludo
  #3 (permalink)  
Antiguo 16/12/2019, 07:27
Avatar de Hyemin  
Fecha de Ingreso: agosto-2014
Mensajes: 147
Antigüedad: 10 años, 3 meses
Puntos: 0
Respuesta: Error con CORS en API REST

Cita:
Iniciado por prueba230683 Ver Mensaje
Pues entonces el problema está en el cliente, o sea en cómo realizas la petición con JavaScript.

Según lo que he leído de ese error, posiblemente se deba a que el navegador no espera recibir contenido application/vnd.sun.wadl+xml del servidor porque en la cabecera Accept de la petición has indicado otra cosa distinta (ej. application/xml).

Te recomiendo mostrar el código JavaScript que hace la petición para que podamos localizar el problema.

Un saludo
Gracias por tu respuesta, estoy usando Angular8 del lado del cliente y este es el metodo


Código Javascript:
Ver original
  1. import { HttpClient } from '@angular/common/http';
  2.  
  3.   constructor(public http: HttpClient, public router: Router, private subir: SubirarchivoService) {
  4.     this.cargarStorage();
  5.    }
  6.  loginLDAP(usuario: string, pass:string, recuerdame: boolean){
  7.  
  8.     if (recuerdame){
  9.       localStorage.setItem('username', usuario)
  10.     } else {
  11.       localStorage.removeItem('username');
  12.     }
  13.  
  14.     let url = environment.urlLDAP+"/login";
  15.  
  16.     return this.http.post(url, {usuario, pass});
  17.  
  18.   }

Última edición por Hyemin; 16/12/2019 a las 07:39
  #4 (permalink)  
Antiguo 16/12/2019, 09:02
 
Fecha de Ingreso: abril-2011
Mensajes: 170
Antigüedad: 13 años, 7 meses
Puntos: 68
Respuesta: Error con CORS en API REST

En el código del primer post:

Código Java:
Ver original
  1. .header("Access-Control-Allow-Headers: 'application/json'",
  2.         "origin, content-type, accept, authorization")

creo que debería ser:

Código Java:
Ver original
  1. .header("Access-Control-Allow-Headers",
  2.         "origin, content-type, accept, authorization")

  #5 (permalink)  
Antiguo 16/12/2019, 09:10
Avatar de Hyemin  
Fecha de Ingreso: agosto-2014
Mensajes: 147
Antigüedad: 10 años, 3 meses
Puntos: 0
Respuesta: Error con CORS en API REST

Cita:
Iniciado por prueba230683 Ver Mensaje
En el código del primer post:

Código Java:
Ver original
  1. .header("Access-Control-Allow-Headers: 'application/json'",
  2.         "origin, content-type, accept, authorization")

creo que debería ser:

Código Java:
Ver original
  1. .header("Access-Control-Allow-Headers",
  2.         "origin, content-type, accept, authorization")


Gracias por la respuesta, acabo de probar eso y sigue sin funcionar :( da el mismo error de CORS
Código:
Access to XMLHttpRequest at 'http://192.168.38.7:8080/rest2/webresources/login' from origin 'http://localhost:4200' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
core.js:6014 ERROR
Código:
zone-evergreen.js:2952 Cross-Origin Read Blocking (CORB) blocked cross-origin response http://192.168.38.137:8080/rest2/webresources/login with MIME type application/vnd.sun.wadl+xml. See https://www.chromestatus.com/feature/5629709824032768 for more details.
  #6 (permalink)  
Antiguo 17/12/2019, 13:04
 
Fecha de Ingreso: abril-2011
Mensajes: 170
Antigüedad: 13 años, 7 meses
Puntos: 68
Respuesta: Error con CORS en API REST

Resulta que la especificación de CORS, por seguridad, no permite usar Access-Control-Allow-Origin: * y Access-Control-Allow-Credentials: true al mismo tiempo, que es lo que estás intentando hacer.

Simplemente cambia el asterisco por el host que estés usando. En tu caso:

Código Java:
Ver original
  1. .header("Access-Control-Allow-Origin", "http://localhost:4200")

Cuando lo pruebes con un dominio real, no te olvides de cambiarlo por el dominio real.

Última edición por prueba230683; 17/12/2019 a las 13:10
  #7 (permalink)  
Antiguo 18/12/2019, 08:41
Avatar de Hyemin  
Fecha de Ingreso: agosto-2014
Mensajes: 147
Antigüedad: 10 años, 3 meses
Puntos: 0
Respuesta: Error con CORS en API REST

Cita:
Iniciado por prueba230683 Ver Mensaje
Resulta que la especificación de CORS, por seguridad, no permite usar Access-Control-Allow-Origin: * y Access-Control-Allow-Credentials: true al mismo tiempo, que es lo que estás intentando hacer.

Simplemente cambia el asterisco por el host que estés usando. En tu caso:

Código Java:
Ver original
  1. .header("Access-Control-Allow-Origin", "http://localhost:4200")

Cuando lo pruebes con un dominio real, no te olvides de cambiarlo por el dominio real.
Gracias,

Intente eso pero me sigue dando el mismo error de CORS, igual necesitaria que cualquier IP pudiera acceder a esta API REST por lo que necesitaria alguna forma de habilitar el CORS general

Código Java:
Ver original
  1. @POST
  2.     //@Consumes("application/x-www-form-urlencoded")
  3.     @Produces(MediaType.APPLICATION_JSON)
  4.     //@CrossOrigin()
  5.     public Response login(@HeaderParam("usuario") String usuario,
  6.             @HeaderParam("pass") String pass) {
  7.  
  8.         Usuario u = new Usuario();
  9.         u.usuario = usuario;
  10.         u.rol = "ADMIN";
  11.  
  12.        
  13.         LdapService ld = new LdapService();
  14.         LdapUser usuarioActual = new LdapUser();
  15.         try {
  16.             usuarioActual = ld.validarUsuario(usuario, pass);
  17.         } catch (LDAPException ex) {
  18.             Logger.getLogger(LoginResource.class.getName()).log(Level.SEVERE, null, ex);
  19.         }
  20.         String respuesta = "";
  21.        
  22.         u.usuario = usuarioActual.getNombre();
  23.         u.rol = usuarioActual.getRol();
  24.  
  25.        return Response
  26.       .status(Response.Status.OK)
  27.       .header("Access-Control-Allow-Origin", "http://192.168.1.8:4200, http://localhost:4200")
  28.       //.header("Access-Control-Allow-Credentials", "true")
  29.       .header("Access-Control-Allow-Headers",
  30.         "origin, content-type, accept, authorization")
  31.       .header("Access-Control-Allow-Methods",
  32.         "GET, POST, PUT, DELETE, OPTIONS, HEAD")
  33.       .entity(u)
  34.       .build();
  35.  
  36.        
  37.     }
  #8 (permalink)  
Antiguo 19/12/2019, 07:32
 
Fecha de Ingreso: abril-2011
Mensajes: 170
Antigüedad: 13 años, 7 meses
Puntos: 68
Respuesta: Error con CORS en API REST

Con el código que muestras, solamente estás enviando las cabeceras de CORS cuando el método de la petición es POST.

También debes enviar todas esas cabeceras cuando el método es OPTIONS, ya que el navegador hace una petición de prueba o preflight (con el método OPTIONS) antes de realizar la petición POST definitiva.

La solución es utilizar un filtro como este: https://stackoverflow.com/a/36619749

Editándolo un poco, si quieres dar acceso a cualquier dominio puedes crear la siguiente clase ResponseCorsFilter:

Código Java:
Ver original
  1. import javax.ws.rs.container.ContainerRequestContext;
  2. import javax.ws.rs.container.ContainerResponseContext;
  3. import javax.ws.rs.container.ContainerResponseFilter;
  4. import javax.ws.rs.core.MultivaluedMap;
  5. import javax.ws.rs.ext.Provider;
  6. import java.io.IOException;
  7.  
  8. public class ResponseCorsFilter implements ContainerResponseFilter {
  9.  
  10.     @Override
  11.     public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext) throws IOException {
  12.  
  13.         MultivaluedMap<String, Object> responseHeaders = responseContext.getHeaders();
  14.         String origin = requestContext.getHeaderString("Origin");
  15.  
  16.         responseHeaders.putSingle("Access-Control-Allow-Origin", origin);
  17.         responseHeaders.putSingle("Access-Control-Allow-Methods", "GET, POST, OPTIONS, PUT, DELETE, HEAD");
  18.         responseHeaders.putSingle("Access-Control-Allow-Credentials", "true");
  19.  
  20.         String reqHead = requestContext.getHeaderString("Access-Control-Request-Headers");
  21.  
  22.         if (null != reqHead && !reqHead.equals("")) {
  23.                 responseHeaders.putSingle("Access-Control-Allow-Headers", reqHead);
  24.         }
  25.     }
  26. }

Por otra parte, para que dicho filtro funcione debes editar el fichero web.xml de tu servidor.

En el web.xml debes añadir dentro de la etiqueta <web-app> lo siguiente:

Código XML:
Ver original
  1. <filter>
  2.         <filter-name>miFiltro</filter-name>
  3.         <filter-class>ResponseCorsFilter</filter-class>
  4. </filter>
  5.  
  6. <filter-mapping>
  7.         <filter-name>miFiltro</filter-name>
  8.         <url-pattern>/aqui/la/ruta/del/api</url-pattern>
  9. </filter-mapping>

Simplemente debes reemplazar "/aqui/la/ruta/del/api" por la ruta de tu API donde quieres que se incluyan las cabeceras de CORS.

Última edición por prueba230683; 19/12/2019 a las 13:18
  #9 (permalink)  
Antiguo 19/12/2019, 14:24
Avatar de Hyemin  
Fecha de Ingreso: agosto-2014
Mensajes: 147
Antigüedad: 10 años, 3 meses
Puntos: 0
Respuesta: Error con CORS en API REST

Cita:
Iniciado por prueba230683 Ver Mensaje
Con el código que muestras, solamente estás enviando las cabeceras de CORS cuando el método de la petición es POST.

También debes enviar todas esas cabeceras cuando el método es OPTIONS, ya que el navegador hace una petición de prueba o preflight (con el método OPTIONS) antes de realizar la petición POST definitiva.

La solución es utilizar un filtro como este: https://stackoverflow.com/a/36619749

Editándolo un poco, si quieres dar acceso a cualquier dominio puedes crear la siguiente clase ResponseCorsFilter:

Código Java:
Ver original
  1. import javax.ws.rs.container.ContainerRequestContext;
  2. import javax.ws.rs.container.ContainerResponseContext;
  3. import javax.ws.rs.container.ContainerResponseFilter;
  4. import javax.ws.rs.core.MultivaluedMap;
  5. import javax.ws.rs.ext.Provider;
  6. import java.io.IOException;
  7.  
  8. public class ResponseCorsFilter implements ContainerResponseFilter {
  9.  
  10.     @Override
  11.     public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext) throws IOException {
  12.  
  13.         MultivaluedMap<String, Object> responseHeaders = responseContext.getHeaders();
  14.         String origin = requestContext.getHeaderString("Origin");
  15.  
  16.         responseHeaders.putSingle("Access-Control-Allow-Origin", origin);
  17.         responseHeaders.putSingle("Access-Control-Allow-Methods", "GET, POST, OPTIONS, PUT, DELETE, HEAD");
  18.         responseHeaders.putSingle("Access-Control-Allow-Credentials", "true");
  19.  
  20.         String reqHead = requestContext.getHeaderString("Access-Control-Request-Headers");
  21.  
  22.         if (null != reqHead && !reqHead.equals("")) {
  23.                 responseHeaders.putSingle("Access-Control-Allow-Headers", reqHead);
  24.         }
  25.     }
  26. }

Por otra parte, para que dicho filtro funcione debes editar el fichero web.xml de tu servidor.

En el web.xml debes añadir dentro de la etiqueta <web-app> lo siguiente:

Código XML:
Ver original
  1. <filter>
  2.         <filter-name>miFiltro</filter-name>
  3.         <filter-class>ResponseCorsFilter</filter-class>
  4. </filter>
  5.  
  6. <filter-mapping>
  7.         <filter-name>miFiltro</filter-name>
  8.         <url-pattern>/aqui/la/ruta/del/api</url-pattern>
  9. </filter-mapping>

Simplemente debes reemplazar "/aqui/la/ruta/del/api" por la ruta de tu API donde quieres que se incluyan las cabeceras de CORS.

Gracias por tu respuesta, intente eso pero ahora no me levanta el WAR y da este error

Código:
19/12/2019 05:22:24 PM org.glassfish.jersey.servlet.init.JerseyServletContainerInitializer addServletWithApplication
INFO: Registering the Jersey servlet application, named servicios.ApplicationConfig, at the servlet mapping /webresources/*, with the Application class of the same name.
19/12/2019 05:22:24 PM org.springframework.web.context.ContextLoader initWebApplicationContext
INFO: Root WebApplicationContext: initialization started
19/12/2019 05:22:24 PM org.springframework.context.support.AbstractApplicationContext prepareRefresh
INFO: Refreshing Root WebApplicationContext: startup date [Thu Dec 19 17:22:24 GMT-03:00 2019]; root of context hierarchy
19/12/2019 05:22:24 PM org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
INFO: Loading XML bean definitions from ServletContext resource [/WEB-INF/applicationContext.xml]
19/12/2019 05:22:24 PM org.springframework.web.context.ContextLoader initWebApplicationContext
INFO: Root WebApplicationContext: initialization completed in 310 ms
19/12/2019 05:22:24 PM org.apache.catalina.core.StandardContext startInternal
GRAVE: Error filterStart
19/12/2019 05:22:24 PM org.apache.catalina.core.StandardContext startInternal
GRAVE: Falló en arranque del Contexto [/rest2] debido a errores previos
19/12/2019 05:22:24 PM org.springframework.context.support.AbstractApplicationContext doClose
INFO: Closing Root WebApplicationContext: startup date [Thu Dec 19 17:22:24 GMT-03:00 2019]; root of context hierarchy

Mi web.xml es

Código XML:
Ver original
  1. <filter>
  2.         <filter-name>miFiltro</filter-name>
  3.         <filter-class>ResponseCorsFilter</filter-class>
  4. </filter>
  5.  
  6. <filter-mapping>
  7.         <filter-name>miFiltro</filter-name>
  8.         <url-pattern>/login</url-pattern>
  9. </filter-mapping>
  #10 (permalink)  
Antiguo 19/12/2019, 15:43
 
Fecha de Ingreso: abril-2011
Mensajes: 170
Antigüedad: 13 años, 7 meses
Puntos: 68
Respuesta: Error con CORS en API REST

No sé, prueba creando con tu IDE un paquete com.ejemplo.filtros:

Código Java:
Ver original
  1. package com.ejemplo.filtros;
  2.  
  3. import javax.ws.rs.container.ContainerRequestContext;
  4. import javax.ws.rs.container.ContainerResponseContext;
  5. import javax.ws.rs.container.ContainerResponseFilter;
  6. import javax.ws.rs.core.MultivaluedMap;
  7. import javax.ws.rs.ext.Provider;
  8. import java.io.IOException;
  9.  
  10. public class ResponseCorsFilter implements ContainerResponseFilter {
  11.  
  12.     @Override
  13.     public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext) throws IOException {
  14.  
  15.         MultivaluedMap<String, Object> responseHeaders = responseContext.getHeaders();
  16.         String origin = requestContext.getHeaderString("Origin");
  17.  
  18.         responseHeaders.putSingle("Access-Control-Allow-Origin", origin);
  19.         responseHeaders.putSingle("Access-Control-Allow-Methods", "GET, POST, OPTIONS, PUT, DELETE, HEAD");
  20.         responseHeaders.putSingle("Access-Control-Allow-Credentials", "true");
  21.  
  22.         String reqHead = requestContext.getHeaderString("Access-Control-Request-Headers");
  23.  
  24.         if (null != reqHead && !reqHead.equals("")) {
  25.                 responseHeaders.putSingle("Access-Control-Allow-Headers", reqHead);
  26.         }
  27.     }
  28. }

Y luego referéncialo como com.ejemplo.filtros.ResponseCorsFilter:

Código XML:
Ver original
  1. <filter>
  2.         <filter-name>miFiltro</filter-name>
  3.         <filter-class>com.ejemplo.filtros.ResponseCorsFilter</filter-class>
  4. </filter>
  5.  
  6. <filter-mapping>
  7.         <filter-name>miFiltro</filter-name>
  8.         <url-pattern>/login</url-pattern>
  9. </filter-mapping>

Si esto no funciona, la última opción que me queda es añadir las cabeceras vía .htaccess.

Última edición por prueba230683; 19/12/2019 a las 22:30

Etiquetas: api, json, post, rest
Atención: Estás leyendo un tema que no tiene actividad desde hace más de 6 MESES, te recomendamos abrir un Nuevo tema en lugar de responder al actual.
Respuesta




La zona horaria es GMT -6. Ahora son las 11:27.