1. 개요

A의 이전 게시물 , 우리는 간 리소스 공유 (CORS) 사양 및 방법 Spring에서 그것을 사용하는 방법에 대해 배웠습니다.

이 빠른 사용방법(예제)에서는 Spring의 5 WebFlux 프레임워크를 사용하여 유사한 CORS 구성을 설정합니다  .

우선 어노테이션 기반 API에서 메커니즘을 활성화하는 방법을 살펴보겠습니다.

그런 다음 전체 프로젝트에서 전역 구성으로 또는 특수 WebFilter 를 사용하여 활성화하는 방법을 분석합니다  .

2. 어노테이션이 달린 요소에서 CORS 활성화

Spring은 컨트롤러 클래스 및/또는 핸들러 메서드에 대한 CORS 요청을 활성화하기 위해 @CrossOrigin 어노테이션을 제공합니다 .

2.1. 요청 처리기 메서드에서 @CrossOrigin 사용 

매핑된 요청 메서드에 이 어노테이션을 추가해 보겠습니다.

@CrossOrigin
@PutMapping("/cors-enabled-endpoint")
public Mono<String> corsEnabledEndpoint() {
    // ...
}

우리는 WebTestClient  ( 이 게시물 의 '4. 테스팅' 섹션에서 설명한 대로 )를 사용하여 이 끝점에서 얻은 응답을 분석합니다.

ResponseSpec response = webTestClient.put()
  .uri("/cors-enabled-endpoint")
  .header("Origin", "http://any-origin.com")
  .exchange();

response.expectHeader()
  .valueEquals("Access-Control-Allow-Origin", "*");

또한 CORS 구성이 예상대로 작동하는지 확인하기 위해 실행 전 요청을 시도할 수 있습니다.

ResponseSpec response = webTestClient.options()
  .uri("/cors-enabled-endpoint")
  .header("Origin", "http://any-origin.com")
  .header("Access-Control-Request-Method", "PUT")
  .exchange();

response.expectHeader()
  .valueEquals("Access-Control-Allow-Origin", "*");
response.expectHeader()
  .valueEquals("Access-Control-Allow-Methods", "PUT");
response.expectHeader()
  .exists("Access-Control-Max-Age");

@CrossOrigin의 어노테이션에는 다음과 같은 기본 구성을 가지고 :

  • 모든 출처 허용(응답 헤더의 '*' 값을 설명함)
  • 모든 헤더 허용
  • 핸들러 메소드에 의해 매핑된 모든 HTTP 메소드가 허용됩니다.
  • 자격 증명이 활성화되지 않았습니다.
  • 'max-age' 값은 1800초(30분)입니다.

그러나 어노테이션의 매개변수를 사용하여 이러한 값을 재정의할 수 있습니다.

2.2. 컨트롤러에서 @CrossOrigin 사용 

이 어노테이션은 클래스 수준에서도 지원되며 모든 메서드에 영향을 미칩니다.

클래스 수준 구성이 모든 메서드에 적합하지 않은 경우 두 요소에 어노테이션을 달아 원하는 결과를 얻을 수 있습니다.

@CrossOrigin(value = { "http://allowed-origin.com" },
  allowedHeaders = { "Baeldung-Allowed" },
  maxAge = 900
)
@RestController
public class CorsOnClassController {

    @PutMapping("/cors-enabled-endpoint")
    public Mono<String> corsEnabledEndpoint() {
        // ...
    }

    @CrossOrigin({ "http://another-allowed-origin.com" })
    @PutMapping("/endpoint-with-extra-origin-allowed")
    public Mono<String> corsEnabledWithExtraAllowedOrigin() {
        // ...
    }

    // ...
}

3. 전역 구성에서 CORS 활성화

WebFluxConfigurer 구현 addCorsMappings() 메서드를 재정의하여 전역 CORS 구성을 정의할 수도 있습니다 .

또한 구현 은 일반 Spring 애플리케이션에서 Spring WebFlux 구성을 가져오기 위해 @EnableWebFlux 어노테이션이 필요합니다 . Spring Boot를 사용하는 경우 자동 구성을 재정의하려는 경우에만 이 어노테이션이 필요합니다.

@Configuration
@EnableWebFlux
public class CorsGlobalConfiguration implements WebFluxConfigurer {

    @Override
    public void addCorsMappings(CorsRegistry corsRegistry) {
        corsRegistry.addMapping("/**")
          .allowedOrigins("http://allowed-origin.com")
          .allowedMethods("PUT")
          .maxAge(3600);
    }
}

결과적으로 특정 경로 패턴에 대해 교차 출처 요청 처리를 활성화합니다.

기본 구성은 @CrossOrigin 구성과 유사 하지만 GET , HEADPOST  메서드만 허용됩니다.

이 구성을 로컬 구성과 결합할 수도 있습니다.

  • 다중 값 속성의 경우 결과 CORS 구성은 각 사양이 추가됩니다.
  • 반면에 단일 값의 경우 로컬 값이 전역 값보다 우선합니다.

그러나 이 접근 방식을 사용하는 것은 기능적 엔드포인트에는 효과적이지 않습니다.

4. WebFilter로 CORS 활성화

기능적 끝점에서 CORS를 활성화하는 가장 좋은 방법은 WebFilter 를 사용하는 것 입니다.

이 게시물에서 보았듯이  WebFilter 를 사용 하여 끝점의 구현을 그대로 유지하면서 요청과 응답을 수정할 수 있습니다.

Spring은  cross-origin 설정을 쉽게 다룰 수 있도록 내장 CorsWebFilter를 제공합니다 .

@Bean
CorsWebFilter corsWebFilter() {
    CorsConfiguration corsConfig = new CorsConfiguration();
    corsConfig.setAllowedOrigins(Arrays.asList("http://allowed-origin.com"));
    corsConfig.setMaxAge(8000L);
    corsConfig.addAllowedMethod("PUT");
    corsConfig.addAllowedHeader("Baeldung-Allowed");

    UrlBasedCorsConfigurationSource source =
      new UrlBasedCorsConfigurationSource();
    source.registerCorsConfiguration("/**", corsConfig);

    return new CorsWebFilter(source);
}

이것은 어노테이션 처리된 핸들러에도 효과적이지만 더 세분화된 @CrossOrigin  구성 과 결합할 수 없습니다  .

우리는 것을 명심해야 CorsConfiguration는 기본 구성이 없습니다.

따라서 모든 관련 속성을 지정하지 않는 한 CORS 구현은 상당히 제한적입니다.

기본값을 설정하는 간단한 방법은  객체 에서 applyPermitDefaultValues() 메서드를 사용하는 것입니다.

5. 결론

결론적으로, 우리는 webflux 기반 서비스에서 CORS를 활성화하는 방법에 대한 아주 짧은 예를 통해 배웠습니다.

우리는 다양한 접근 방식을 보았으므로 이제 우리의 요구 사항에 가장 적합한 접근 방식을 분석하기만 하면 됩니다.

이 주제와 관련된 대부분의 엣지 케이스를 분석하는 테스트 케이스와 함께 GitHub 리포지토리 에서 많은 예를 찾을 수 있습니다 .

Generic footer banner