Pink Spider/PreFlightCorsConfig_example

Created Mon, 31 Mar 2025 00:49:17 +0900 Modified Mon, 08 Dec 2025 08:41:47 +0900
632 Words 3 min

PreFlightCorsConfig example

@Configuration
public class PreFlightCorsConfig {

    private final CorsProperties corsProperties;

    public PreFlightCorsConfig(CorsProperties corsProperties) {
        this.corsProperties = corsProperties;
    }

    private static final String ALLOWED_HEADERS = "x-requested-with,authorization, refresh-token,Access-Control-Allow-Origin,Content-Type, credential,X-AUTH-TOKEN,X-CSRF-TOKEN";

    private static final String ALLOWED_METHODS = "GET, PUT, POST, PATCH, DELETE, OPTIONS";

    private static final String ALLOWED_CREDENTIALS = "true";

    // 중요 해당 헤더가 없다면 axios를 통한 프론트에서 확인이 불가능함
    private static final String EXPOSE_HEADERS = "*,Authorization,Refresh-token,authorization,refresh-token";

    private static final String MAX_AGE = "3600";

    @Bean
    public WebFilter corsFilter() {
        return (ServerWebExchange ctx, WebFilterChain chain) -> {
            ServerHttpRequest request = ctx.getRequest();
            String requestOrigin = request.getHeaders().getOrigin();

            if (CorsUtils.isPreFlightRequest(request)) {
                ServerHttpResponse response = ctx.getResponse();
                HttpHeaders headers = response.getHeaders();

                if (requestOrigin != null && corsProperties.getAllowedOrigins().contains(requestOrigin)) {
                    headers.add("Access-Control-Allow-Origin", requestOrigin);
                }

                headers.add("Access-Control-Allow-Methods", ALLOWED_METHODS);
                headers.add("Access-Control-Max-Age", MAX_AGE);
                headers.add("Access-Control-Allow-Headers", ALLOWED_HEADERS);
                headers.add("Access-Control-Allow-Credentials", ALLOWED_CREDENTIALS);
                headers.add("Access-Control-Expose-Headers", EXPOSE_HEADERS);

                // 프론트에서 해당 헤더를 확인할수잇게 허가해줌
                headers.add("Access-Control-Expose-Headers", EXPOSE_HEADERS);
                if (request.getMethod() == HttpMethod.OPTIONS) {
                    response.setStatusCode(HttpStatus.OK);
                    return Mono.empty();
                }
            }

            return chain.filter(ctx);
        };
    }
}

CorsProperties

@Component
@Getter
@Setter
@ConfigurationProperties(prefix = "app.cors")
public class CorsProperties {

    private List<String> allowedOrigins = new ArrayList<>();
}

설정

  • dev, prod profile 별로 다르게 설정하는 게 일반적
# application-dev.yml
cors:
  allowed-origins:
    - "http://localhost:3000"
    - "http://127.0.0.1:3000"
# application-prod.yml
cors:
  allowed-origins:
    - "https://example.com"
    - "https://another-domain.com"

spspring-cloud-starter-gateway 사용시

Spring Cloud Gateway를 사용하고 있다면 PreFlightCorsConfig 같은 별도의 Java Config 없이도 application.yml에 설정만으로 CORS 처리가 가능합니다.**


✅ TL;DR

✔️ spring.cloud.gateway.globalcors.cors-configurations

이 설정은 Spring Cloud Gateway 전용이며, Gateway 레벨에서 전역적으로 CORS 프리플라이트 요청을 처리합니다.

spring:
  cloud:
    gateway:
      globalcors:
        cors-configurations:
          '[/**]':
            allowedOrigins:
              - "https://dev.pink-spider.io"
            allowedMethods:
              - GET
              - POST
              - OPTIONS
              - PUT
              - DELETE
            allowedHeaders:
              - "*"
            exposedHeaders:
              - "Authorization"
              - "Refresh-token"
            allowCredentials: true

allowedHeaders: "*" 와 같이 와일드카드도 가능합니다 (필요 시 명시적으로 지정 가능).


✅ 언제 PreFlightCorsConfig가 필요한가?

상황 필요 여부
Spring Cloud Gateway 사용 필요 없음 (YAML 설정으로 충분)
Spring WebFlux/Web MVC 단독 서버 ✅ 필요 (Filter 또는 WebMvcConfigurer 필요)
특정 조건 하에서 커스텀 로직이 필요한 경우 ✅ 필요할 수 있음 (예: 다이내믹 Origin 체크 등)

🎯 정리

  • Spring Cloud Gateway를 쓰고 있고, YAML 설정만으로 잘 작동 중이라면 PreFlightCorsConfig는 제거해도 됩니다.
  • 단, 프리플라이트 요청이 제대로 처리되지 않거나, 동적으로 origin을 제어해야 할 필요가 있을 때만 Java 코드 수준에서 커스터마이징이 필요합니다.