Configuración de Nginx y Java para resolver el problema de CORS

Configuración de Nginx como proxy inverso

Se puede utilizar Nginx para agregar los encabezados necesarios de CORS antes de enviar la solicitud al servidor backend. A continuación, se muestra un ejemplo de configuración simplificada en el bloque server de nginx.conf:


location /api/ {
    if ($request_method = 'OPTIONS') {
        add_header 'Access-Control-Allow-Origin' '$http_origin' always;
        add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS' always;
        add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization' always;
        add_header 'Access-Control-Max-Age' 1728000;
        add_header 'Content-Type' 'text/plain; charset=utf-8';
        add_header 'Content-Length' 0;
        return 204;
    }

    add_header 'Access-Control-Allow-Origin' '$http_origin' always;
    add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS' always;
    add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization' always;
    add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range' always;

    proxy_pass http://127.0.0.1:8085;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
}

Implementación en el backend Java

Para una aplicación Java que no utilize un framework como Spring MVC que provea soporte para CORS de manera declarativa, se puede crear un filtro de servlet (Servlet Filter) para gestionar los encabezados. El filtro debe inspeccionar el método de la solicitud y establecer los encabezados apropiados.


import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class CorsFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        // Inicialización si es necesaria.
    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
        HttpServletResponse response = (HttpServletResponse) res;
        HttpServletRequest request = (HttpServletRequest) req;

        // Establecer cabeceras CORS comunes
        String origin = request.getHeader("Origin");
        if (origin == null) {
            origin = "*";
        }
        response.setHeader("Access-Control-Allow-Origin", origin);
        response.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
        response.setHeader("Access-Control-Allow-Headers", "Authorization, Content-Type, X-Requested-With");
        response.setHeader("Access-Control-Max-Age", "3600");

        // Para solicitudes preflight (OPTIONS), devolver un 200 OK inmediatamente.
        if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {
            response.setStatus(HttpServletResponse.SC_OK);
            return;
        }

        chain.doFilter(request, response);
    }

    @Override
    public void destroy() {
        // Limpieza de recursos.
    }
}

Este filtro debe ser registrado en el descriptor de despliegue (web.xml) para que se aplique a las rutas deseadas, por ejemplo, a todas las peticiones que entren a la aplicación.


<filter>
    <filter-name>corsFilter</filter-name>
    <filter-class>com.miapp.filtros.CorsFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>corsFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

Consideraciones de implementación

La elección entre estas dos aproximaciones depende de la arquitectura del proyecto.

  • Solución en Nginx: Centraliza la lógica de CORS en la capa de infraestructura. Es eficiente y no requiere cambios en el código de la aplicación. Sin embargo, su mantenimiento depende de los equipos de operaciones y debe coordinarse cuidadosamente para evitar conflictos con la configuración de la aplicación.
  • Solución en la aplicación Java: Proporciona un control más granular sobre qué recursos pueden ser accedidos desde qué orígenes. La lógica reside junto al código de la aplicación, lo que facilita su versionado y dsepliegue. El principal inconveniente es que se aplica carga adicional a cada petición que procesa el servidor de aplicaciones.

Es crucial validar los orígenes permitidos en producción en lugar de usar un comodín *, especialmente si se manejan credenciales (cookies, autenticación HTTP).

Etiquetas: Nginx java CORS cross-origin servlet-filter

Publicado el 7-3 09:42