CORS заблокирован из-за отсутствия “Access-Control-Allow-Origin” в контейнерном приложении Angular и бэкенде Spring Boot.

Вопрос или проблема

Я создал приложение на Angular и создал образ Docker, который позволяет ему работать на сервере Nginx (после его запуска). Для бэкенда у меня также есть реализованный в Docker проект. При попытке получить доступ к данным с бэкенда я сталкиваюсь с ошибкой, связанной с политикой CORS, в результате чего в браузере я вижу следующее: “…было заблокировано политикой CORS: отсутствует заголовок “Access-Control-Allow-Origin”…”

Чтобы решить эту проблему, я пробовал различные изменения конфигурации на сервере Nginx, например: (1) установить add_header “Access-Control-Allow-Origin” “http://0.0.0.0:8080”, (2) попробовать аналогичное изменение на стороне прокси, proxy_set_header “Access-Control-Allow-Origin” “http://0.0.0.0:8080” и т.д. Но ничего не сработало (обратите внимание, что “http://0.0.0.0:8080” указывает на бэкенд, а доступ к Angular осуществляется через “http://0.0.0.0:7000”).

Пример того, как выглядит мой файл конфигурации, представлен ниже:

server { 
    listen 80;
    location / {
        root /usr/share/nginx/html;
        index index.html index.htm;
        try_files $uri $uri /index.html = 404;
    }

    location /api {
         proxy_pass http://0.0.0.0:8080;
         proxy_set_header "Access-Control-Allow-Origin" "http://0.0.0.0:8080"
     }
}

Может кто-нибудь из вас поделиться идеей, как решить эту проблему?

Спасибо!

Фактически блокировку выполняет веб-клиент (независимо от того, где он размещен в вашей настройке), поэтому вам необходимо разрешить исходный адрес, который клиент намеревается использовать, с внедренным Access-Control-Allow-Origin заголовком.

Этот заголовок и его значение должны быть известны клиенту до отправки запроса (который у вас не проходит), поэтому предыдущий ответ должен был предоставить его.

Как видно из ссылки, синтаксис заголовка не включает в себя номера портов. Насколько мне известно, 0.0.0.0 не является синтаксисом, который CORS интерпретирует так же, как сетевые службы, но я этого не тестировал и могу ошибаться.

Также, насколько я знаю, заголовок не указывает на протокол, а только на fqdn, например, www.example.com.

Я бы предположил, что конкретный IP-адрес может работать вместо fqdn, но не тестировал это и могу ошибаться.

Однако я использовал синтаксис подстановочного знака (*) указанный в ссылке, и это работает. Более специфический адрес предпочтителен, когда это возможно, но можно начать с подстановочного знака и посмотреть, работает ли внедрение заголовка вообще.

Так что попробуйте внедрить Access-Control-Allow-Origin: * , это моя рекомендация.

Нет необходимости добавлять что-либо в конфигурацию nginx, такое как proxy_set_header. Вам нужно добавить фильтр CORS в ваше веб-приложение на Spring и разрешить запросы с разных источников.

Вот так:

@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
@Slf4j
public class CorsFilter implements Filter {

    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
        final HttpServletResponse response = (HttpServletResponse) res;
        log.info("request came for url {}", ((HttpServletRequest) req).getRequestURL());
        response.setHeader("Access-Control-Allow-Origin", "*");
        response.setHeader("Access-Control-Allow-Methods", "POST, PUT, GET, OPTIONS, DELETE");
        response.setHeader("Access-Control-Allow-Headers", "Authorization, Content-Type");
        response.setHeader("Access-Control-Max-Age", "3600");
        if (HttpMethod.OPTIONS.name().equalsIgnoreCase(((HttpServletRequest) req).getMethod())) {
            response.setStatus(HttpServletResponse.SC_OK);
        } else {
            chain.doFilter(req, res);
        }
    }

    @Override
    public void destroy() {
    }

    @Override
    public void init(FilterConfig config) throws ServletException {
    }
}

Ответ или решение

Решение проблемы CORS в Dockerized Angular и Spring Boot приложениях

Введение

Проблема, с которой вы столкнулись, связана с политикой CORS (Cross-Origin Resource Sharing), которая запрещает веб-приложениям делать запросы к источникам, отличным от того, с которого было загружено само приложение. Это защищает пользователей от выполнения потенциально вредоносных запросов.

Основные шаги для решения проблемы

  1. Настройка CORS на стороне Spring Boot:
    Наиболее распространённым и правильным способом решения данной проблемы является добавление CORS-заголовков в вашем Spring Boot приложении. Вместо того, чтобы управлять CORS через Nginx, можно это сделать непосредственно в вашем Spring Boot коде. Вот пример кода, который поможет вам настроить нужные заголовки:

    import javax.servlet.Filter;
    import javax.servlet.FilterChain;
    import javax.servlet.FilterConfig;
    import javax.servlet.ServletException;
    import javax.servlet.ServletRequest;
    import javax.servlet.ServletResponse;
    import javax.servlet.annotation.WebFilter;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import org.springframework.stereotype.Component;
    import org.springframework.core.annotation.Order;
    import org.springframework.http.HttpMethod;
    
    import java.io.IOException;
    
    @Component
    @Order(Ordered.HIGHEST_PRECEDENCE)
    public class CorsFilter implements Filter {
    
       @Override
       public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
           final HttpServletResponse response = (HttpServletResponse) res;
           final HttpServletRequest request = (HttpServletRequest) req;
    
           response.setHeader("Access-Control-Allow-Origin", "*");
           response.setHeader("Access-Control-Allow-Methods", "POST, PUT, GET, OPTIONS, DELETE");
           response.setHeader("Access-Control-Allow-Headers", "Authorization, Content-Type");
           response.setHeader("Access-Control-Max-Age", "3600");
    
           if (HttpMethod.OPTIONS.name().equalsIgnoreCase(request.getMethod())) {
               response.setStatus(HttpServletResponse.SC_OK);
           } else {
               chain.doFilter(req, res);
           }
       }
    
       @Override
       public void init(FilterConfig filterConfig) {}
    
       @Override
       public void destroy() {}
    }

    В этом коде мы устанавливаем заголовок Access-Control-Allow-Origin на ‘*’, что позволит всем доменам делать запросы к вашему серверу. Хотя это и удобно для разработки, желательно использовать конкретные домены (например, http://localhost:7000), когда вы развертываете приложение в продакшен.

  2. Настройка Nginx (если всё же требуется):
    Если вы хотите контролировать CORS через Nginx, измените вашу конфигурацию следующим образом:

    server { 
       listen 80;
    
       location / {
           root /usr/share/nginx/html;
           index index.html index.htm;
           try_files $uri $uri /index.html = 404;
       }
    
       location /api {
           proxy_pass http://0.0.0.0:8080;
           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 "Access-Control-Allow-Origin" "*";
           proxy_set_header "Access-Control-Allow-Methods" "POST, GET, OPTIONS, DELETE, PUT";
           proxy_set_header "Access-Control-Allow-Headers" "Authorization, Content-Type";
       }
    }

    Обратите внимание на то, что мы добавили заголовки CORS в секцию location /api. Это позволит вашему Nginx прокси не блокировать запросы из вашего Angular приложения.

  3. Тестирование:
    После внесения всех необходимых изменений, перезапустите ваши контейнеры Docker и протестируйте, работает ли ваше приложение. Используйте инструменты разработчика в браузере для проверки того, что заголовки CORS корректно устанавливаются в ответах серверов.

Заключение

Настройка CORS – важный аспект разработки веб-приложений. Правильная конфигурация на стороне Spring Boot является ключом к решению проблемы блокировок CORS. Убедитесь, что вы тестируете ваш код в различных средах и проводите аудит безопасности перед тем, как выставлять настройки на продакшен.

Оцените материал
Добавить комментарий

Капча загружается...