728x90
반응형
728x90
반응형
728x90
반응형
SpringBoot 3.3.4
JDK 17
React 18.3.1 

 

스프링부트 RESTful 서비스를 이용해 리액트에서 데이터를 조회하려는데 개발자모드 Console창을 보니 다음과 같이 에러가 발생하였다.

Access to fetch at 'http://localhost:8080/api/items' from origin 'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

 

번역하면

원본 'http://localhost:3000'에서 'http://localhost:8080/api/items'로의 가져오기 액세스가 CORS 정책에 의해 차단되었습니다: 요청된 리소스에 'Access-Control-Allow-Origin' 헤더가 없습니다. 불투명한 응답이 필요한 경우 요청의 모드를 'no-cors'로 설정하여 CORS를 비활성화한 상태에서 리소스를 가져오세요.

 

이와 같은 해석대로 프런트엔드에서 API를 호출할 때 mode: 'no-cors'로 설정 후 호출하면 요청이 성공하더라도 데이터를 정상적으로 가져오지 못하는 오류가 발생한다. 

 

 

 

그래서 CORS 정책을 풀려면 서버 측에서 처리해야 한다. Spring Boot 백엔드에서 관련 컨트롤러에 @CrossOrigin 어노테이션을 추가하여 CORS를 활성화하거나 Spring Boot 구성에서 전역적으로 구성하면 된다. 이렇게 하면 프런트엔드에서 응답에 올바르게 액세스 할 수 있게 된다.

 

React의 서버 주소가 http://localhost:3000 이므로 다음과 같이 @CrossOrigin(origins = "http://localhost:3000")를 추가하였다.

@CrossOrigin(origins = "http://localhost:3000")
@RestController
public class ItemController {
	
	@Autowired
	private ItemRepository itemRepository;
	
	@GetMapping("/items")
	public Iterable<Item> getItems(){
		return itemRepository.findAll();
	}
}

 

그런데 위와 같이 처리했음에도 동일하게 에러가 발생하였다. 

 

반응형
728x90

 

@CrossOrigin 어노테이션을 추가했음에도 에러가 발생했던 건 application.properties 파일에 base-path 설정한 것 때문이었다.

RESTful 서비스의 base path로 /api를 사용하기 위해 spring.data.rest.base-path=/api를 설정했는데 @CrossOrigin 어노테이션은 이를 해결해주지 못하는 것으로 보인다.

 

그래서 해당 속성값을 삭제하고 다음과 같이 Controller 파일에 @RequestMapping("/api")를 추가하는 방식으로 변경하였다.

 

@CrossOrigin(origins = "http://localhost:3000")
@RequestMapping("/api")
@RestController
public class ItemController {
	
	@Autowired
	private ItemRepository itemRepository;
	
	@GetMapping("/items")
	public Iterable<Item> getItems(){
		return itemRepository.findAll();
	}
}

 

더 이상 에러가 발생하지 않고 데이터가 정상적으로 화면에 표시된다.

 

그런데 spring.data.rest.base-path 설정한 값 그대로 사용하고 싶을 때는 어떻게 해야 할까? 이 때 Spring Boot 구성에서 전역적으로 구성하는 방식을 사용해야 한다.

 

import org.springframework.context.annotation.Configuration;
import org.springframework.data.rest.core.config.RepositoryRestConfiguration;
import org.springframework.data.rest.webmvc.config.RepositoryRestConfigurer;
import org.springframework.web.servlet.config.annotation.CorsRegistry;

@Configuration
public class RestConfig implements RepositoryRestConfigurer {
    @Override
    public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config, CorsRegistry cors) {
        cors.addMapping("/**")
            .allowedOrigins("http://localhost:3000")
            .allowedMethods("GET", "POST", "PUT", "DELETE")
            .allowCredentials(true);
    }
}

 

참고로 application.properties 파일에 spring.data.rest.base-path를 설정했을 때와 @RequestMapping 어노테이션을 사용했을 경우 Response의 JSON 형태가 다르다.

 

spring.data.rest.base-path를 설정했을 때는 객체._ embedded.items 키에서 데이터 접근이 가능하다. React에서 data => setItems(data._embedded.items)

 

@RequestMapping 어노테이션을 사용했을 경우는 키 없이 리턴된 배열객체에서 데이터를 가져올 수 있다.

React에서 data => setItems(data)

 

결론

스프링부트의 RESTful 서비스 이용한다면 application.properties 파일에 spring.data.rest.base-path를 사용하고 RepositoryRestConfigurer를 이용한 두 번째 방법으로 처리하는 것이 맞다고 생각된다.

 

 

 

 

728x90
반응형

+ Recent posts