본문 바로가기
프로젝트/FitTrip

[트러블슈팅] 서버 배포간 다양한 CORS 오류

by 진꿈청 2024. 6. 25.

🐞 버그 설명

 

상황

서버 배포를 진행하며 굉장히 다양한 CORS 오류를 직면했다.
그래서 배포를 진행하며 직면한 다양한 CORS 오류를 깃 이슈로 등록하려 한다.

 

발생한 버그

  1. API Gateway에 전역 CORS 필터를 적용했을 경우
  2. CORS 중복 설정으로 인한 오류
  3. STOMP와 관련된 CORS 오류

발생한 버그들을 정리하자면 위와 같이 정리할 수 있다.
순서대로 자세한 버그 내용과 해결 과정을 설명하도록 한다.

 

 

1. API Gateway에 전역 CORS 필터를 적용했을 경우


초기 API Gateway에서는 클라이언트의 요청을 전부 API Gateway가 처리할 것으로 판단하여
CORS와 관련된 설정을 해주는 필터도 API Gateway에 작성하였다.

spring:
  application:
    name: gateway
  cloud:
    gateway:
            ....
      globalcors:
        cors-configurations:
          '[/**]':
            allowedOrigins:
              - 'http://localhost:5173' # 허용하려는 도메인
            allow-credentials: true # 요청 시 인증 정보를 전송하도록 허가
            allowedHeaders: '*' # 허용하려는 헤더
            allowedMethods: # 허용하려는 HTTP 메서드
              - PUT
              - GET
              - POST
              - DELETE
              - OPTIONS
            .....

 

하지만, 이렇게 했을 때 CORS 설정 오류가 발생하였다.

따라서, NGINX에서도 CORS 설정을 추가하는 것으로 변경하였다.

 

Nginx conf

 location /api {
        if ($request_method = 'OPTIONS') {
            add_header 'Access-Control-Allow-Origin' $allowed_origin always;
            add_header 'Access-Control-Allow-Methods' 'GET, POST, DELETE, PATCH, OPTIONS';
            add_header 'Access-Control-Allow-Headers' 'Content-Type, Authorization';
            add_header 'Access-Control-Allow-Credentials' 'true';
            return 204;
        }
        add_header 'Access-Control-Allow-Origin' $allowed_origin always;
        add_header 'Access-Control-Allow-Credentials' 'true';
        proxy_pass http://localhost:8000;
    }

 

NGINX에서 CORS Preflight에서 사용되는 HTTP Method로 CORS 관련 설정을 정의해주었다.
이렇게 했을 때 CORS 관련 설정이 해결된 줄 알았으나 2번 문제가 발생했다.

 

 

2. CORS 중복 설정으로 인한 오류

header contains multiple values 'http://localhost:3000, http://localhost:3000', but only one is allowed.

 

위 오류는 CORS 설정이 중복되었을 때 생기는 오류이다.

크롬창의 개발자 도구 네트워크로 확인해보았을 때 Origin 설정이 중복되어 들어가있었다.
이는 NGINX와 API Gateway에서 CORS 관련 헤더가 2번 들어가서 클라이언트 쪽에서 CORS 오류가 발생하는 것이다.

 

API Gateway에서 CORS 설정을 제거하여도 몇몇 서비스에서 해당 중복 설정 오류가 발생했는데,
이는 각 서비스에서도 마찬가지로 CORS 설정이 중복될 수 있기 때문이다.(기존에  CORS 설정이 되어있던 서비스들)

 

따라서, 공통적인 관리를 위해 NGINX를 제외한 모든 서비스에서 CORS 설정을 빼주었고 그때부터는 정상 작동이 되었다.

 

 

3. STOMP와 관련된 CORS 오류

 

위의 설정만으로, 전체 서비스에 관한 CORS 오류가 해결된 것으로 보였으나 웹 소켓을 사용하는 채팅 서비스에서는 해결되지 않았다.
(이때도, 2번과 마찬가지로 중복 설정 오류가 발생하였다.)

 

당시 생각해볼 수 있는 경우의 수는 채팅 서비스에 별도의 CORS 설정 여부였다.
하지만, Nginx를 제외한 모든 서비스 CORS 제거과정에서 제거했으므로 불가능한 경우였다.

 

그러던 중 채팅 서비스 STOMP 관련 설정에서 @Override된 Origin과 관련된 메소드를 발견하였고

해당 메소드 설정으로 인한 중복으로 판단하여 관련 설정을 제거하였다.

 

관련 메소드

    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/ws-stomp")
		.setAllowedOriginPatterns("http://localhost:3000")
                .withSockJS();
    }

 

하지만, 이는 CORS 설정 중복을 해결할 뿐 여전히 정상적인 네트워크 통신이 이루어지지 않았다.

 

관련된 STOMP, SockJS 정보를 찾던 중 웹 소켓 방식은 기존의 CORS 정책과 약간의 차이점이 있음을 발견하였다.
(자세한 설명은 #113 을 참고하면 된다.)

 

즉, 웹 소켓 및 STOMP의 Origin 인증 방식은 CORS의 HTTP Method OPTIONS 방식과 다르다.

따라서, 채팅 서비스로 가는 요청에 관한 NGINX 설정을 변경해주었다. (기존의 OPTIONS 메소드 확인 코드 제거)

 

변경 전

  location /stomp {
      if ($request_method = 'OPTIONS') {
          add_header 'Access-Control-Allow-Origin' $allowed_origin always;
          add_header 'Access-Control-Allow-Methods' 'GET, POST, DELETE, PATCH, OPTIONS';
          add_header 'Access-Control-Allow-Headers' 'Content-Type';
          add_header 'Access-Control-Allow-Credentials' 'true';
          return 204;
      }
      proxy_pass http://localhost:8000;
      proxy_set_header Host $http_host;
      proxy_set_header X-Real-IP $remote_addr;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_http_version 1.1;       
      proxy_set_header Upgrade $http_upgrade;
      proxy_set_header Connection "upgrade";
  }

 

변경 후


  location /stomp {
  #    if ($request_method = 'OPTIONS') {
  #        add_header 'Access-Control-Allow-Origin' $allowed_origin always;
  #        add_header 'Access-Control-Allow-Methods' 'GET, POST, DELETE, PATCH, OPTIONS';
  #        add_header 'Access-Control-Allow-Headers' 'Content-Type';
  #        add_header 'Access-Control-Allow-Credentials' 'true';
  #        return 204;
  #    }
      proxy_pass http://localhost:8000;
      proxy_set_header Host $http_host;
      proxy_set_header X-Real-IP $remote_addr;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_http_version 1.1;       
      proxy_set_header Upgrade $http_upgrade;
      proxy_set_header Connection "upgrade";
  }

 

이 밖에도 CORS 오류로 토큰 관련된 오류는 CORS의 Credential 오류로 클라이언트에게 보여지는 등 다양하게 발생한다.


CORS의 이론 자체는 그렇게 어렵지 않지만, 네트워크에서 일어나는 작업들과 밀접한 관계가 있음에 주의해야 할 것 같다.