리액트 - 스프링부트 연동 CORS 이슈 해결!

Lenny·2022년 5월 2일
4

팀 프로젝트를 진행하다가 스프링부트React를 연동해야 하는 상황을 마주했다.

백엔드와 연동할 때 CORS 이슈에 대한 내용은 Express.js 연동할 때 이미 한번 겪어 보았고, 인터넷을 통해서 인지를 하고 있었지만, 막상 마주하니깐 혼란스러웠다.

하지만 백엔드와 프론트엔드단이 어떻게 데이터를 주고받아야하고 CORS 이슈가 왜 발생하는지에 대해 자세히는 아니더라도 대충은 알고 있었다!

CORS에 대해서는 공부하고 나중에 기록해놓아야겠다.

그래서 오늘은 이 이슈를 어떻게 해결했는지 작성해보려고한다.

해결 과정

첫 번째 해결

우선 처음에 리액트와 스프링부트를 연동하기 위해서 첫번째로 시도한 방법은 리액트 프로젝트 폴더의 package.jsonproxy를 추가하는것이었다.

리액트는 localhost:3000에서 동작하고, 서버(스프링부트)는 localhost:8082 위에서 동작한다.

리액트에서 localhost:8082 로 요청했을 때, 응답을 받아야하는데 따로 설정없이는 받지 못한다.

그래서 따로 설정을 해줘야하는데, 널리 알려진 방법이 package.jsonproxy를 설정해주는 방법이다.

이런식으로 설정해준다.

근데 여기서 문제가 발생했다. 내 개인 노트북에서는 문제없이 작동이 됬는데, 학원 컴퓨터에서는 다음과 같은 에러가 출력되면서 리액트 앱이 실행조차 되지 않았다.


Invalid options object. Dev Server has been initialized using an options object that does not match the API schema.

  • options.allowedHosts[0] should be a non-empty string.

해결을 하려고 구글링을 했는데, 내가 겪은 상황과 똑같은 상황을 겪은 분이 계셨다.
https://velog.io/@yunso/%EB%A6%AC%EC%95%A1%ED%8A%B8-%ED%94%84%EB%A1%9D%EC%8B%9C-%EC%97%90%EB%9F%AC
이 분은 유선랜 대신 핫스팟을 사용하여 해결했지만, 우리는 그럴 수 있는 환경이 아니었다.

그런데 리액트에서 프록시 설정을 도와주는 라이브러리가 있다는 걸 알게되었다.

http-proxy-middleware 라는 라이브러리였다.

이 라이브러리를 사용하면, package.jsonproxy 를 추가하는것 대신 다른 방법으로 proxy 를 설정한다.

proxy 설정 과정

  1. npm i http-proxy-middleware 를 터미널에 입력하고 라이브러리 설치

  2. src 폴더 내부에 setProxy.js 파일 생성

  1. 파일 내부는 다음과 같이 작성
const { createProxyMiddleware } = require("http-proxy-middleware");

module.exports = function (app) {
  app.use(
    createProxyMiddleware("/api/v1", {
      target: "http://localhost:8082",
      changeOrigin: true,
    })
  );
};

프록시를 위 방법으로 설정해주니까 리액트를 실행하는데에선 에러가 발생하지 않았다!

두번째 해결

이제 리액트에서 백엔드에 요청을 보내야한다.

그런데 역시 예상대로 에러가 발생한다.

Access to XMLHttpRequest at 'http://localhost:8082/Join.do' from origin 'http://localhost:3000' has been blocked by CORS policy : Response to preflight request doesn't pass access control check: 'Access-Control-Allow-Origin' header is present on the requested resouce.

위와 같은 에러가 발생한다.

그래서 알아보니깐, 스프링부트쪽에서도 CORS 관련하여 설정해주는 코드를 작성해야한다고 한다.

설정 과정

  1. 위와 같이 WebMvcConfig 클래스파일을 생성한다.

  2. 클래스 파일 내부는 다음과 같이 작성한다.

++
여러 블로그를 살펴봤지만, 이 부분을 설정하는 방법은 다양하다.
나는 https://devlog-wjdrbs96.tistory.com/429 이 블로그를 참고하여 작성했다.


이렇게 설정해주었더니

Access to XMLHttpRequest at 'http://localhost:8082/Join.do' from origin 'http://localhost:3000' has been blocked by CORS policy : Response to preflight request doesn't pass access control check: 'Access-Control-Allow-Origin' header is present on the requested resouce.

위 에러메시지는 더 이상 출력되지 않았다.

세번째 해결

하지만 아직 끝난게 아니었다.

이번엔 다른 에러를 볼 수 있었다.

그래서 뭐가 문제인가 고민을 많이했다.

아니 분명 설정할 건 다 설정한 것 같은데..? 우리 프로젝트는 아직 스프링 시큐리티 적용도 하지 않았는데..?

이건 뭐지?? 싶었다.

에러메시지를 읽고 추측해보니 프론트에서 HTTP ok status를 못받는다는 에러 같았다.

그래서 난 생각해봤다.

테스트용으로 http://localhost:8082/Join.do 주소에 요청을 보냈을때 서버에서 "success" 라는 문자열을 리턴하도록 컨트롤러에 코드를 작성해놨는데, 혹시 HTTP 상태 코드를 리턴해야하나 싶었다.

그래서 ResponseEntity 객체를 생성하고, HttpStatus.OK 을 리턴하도록 메서드를 수정했는데도 같은 오류가 출력됐다.

그래서 코드를 다시한번 살펴봤더니, 백엔드에서 맵핑하는 경로가 http://localhost:8082/Join.do 이 아니라 http://localhost:8082/join.do 이었다...

내가 눈으로 확인했어야했는데! 그대로 코드를 전달받고 급하게 연동하느라 확인을 제대로 못했다 ㅠㅠㅠ..

그래서 백엔드 맵핑 설정을 join.do 로 바꾸고 요청을 보냈더니...

된다! 프론트랑 백엔드랑 통신이 된다고!

감격스러운 순간이었다.

이제 이렇게 마무리하고 깃에 PUSH 했다!

네번째 해결

이렇게 잘 마무리 되는줄 알았으나, 한 가지 고려하지 못한점이 또 있었다.

이건 내가 원인을 아는 부분이라 해결하는데 어려움이 없었다.

우선 내가 백엔드로 데이터를 넘길때, JSON.stringifyJSON 을 문자열로 바꿔서 보냈어야했는데 이걸 깜빡했다.

이렇게 보냈어야했는데, data를 그냥 쌩으로 보내버렸던것..

그리고 스프링부트에서 이렇게 전달 된 데이터를 받을때, 문자열로 보냈으니까 String으로 받으면 되겠지? 라고 생각했지만 이건 Wrong Think 였다.

저렇게 JSON 을 문자열로 바꾸고 보냈는데 왜 안돼지? 맞는데 왜 안돼? 를 연달아 외친 내가 부끄러웠다.

전혀 맞는게 아니었다.

스프링에서 JSON 을 받을때 String이 아니라 HashMap 자료형으로 받아야한다.. ㅎ

스프링에서 해당 메서드의 매개변수 타입을 HashMap 으로 바꾸고 받으니깐 아주 잘 받아진다!

마무리

처음 마주하는 이슈였는데 이슈를 잘 해결해서 뿌듯하다.

이번 이슈를 해결하면서 여러가지를 배웠다.

혼자 개발을 공부할 땐 백엔드와 연동하지 않는 간단한 프로젝트를 진행했었고, 풀스택 프로젝트를 진행했어도 리액트를 사용하지 않는 프로젝트를 진행했었다.
(요즘은 Next.js를 공부하고있다.)

리액트와 다른 프레임워크와의 연동은 오늘이 처음이었다!

오늘은 조금 제대로 원인을 알고 해결한 느낌보다는 운 좋게 해결한 느낌이 들지만 CORS 에 대해 공부하면 다음부턴 이런 이슈가 발생하면 좀 더 "실력" 으로 해결 할 수 있을 것 같은 기분이 든다.
( + 추가적으로 SOP도 공부해야할 것 같다. 이것도 CORS와 더불어 연동할 때 자주 뜨는 이슈같았다. 아직 경험하진 않았지만, 이제 곧 마주해야 할 이슈같다.. 미리 예습해둬야겠다.)

아무튼 이제 본격적으로 백엔드 담당하는 팀원들과 협업을 할 수 있게 됐다!! 우효!

역시 코딩하는 맛은 이맛 아니겠슴까 ! ㅋ

profile
🧑‍💻

1개의 댓글

comment-user-thumbnail
2023년 6월 17일

혹시 그렇게 해서 스프링 데이터 넘기고 가져올 때 백엔드 쪽도 프로젝트를 실행 중이었나요? 그리고 둘이 같은 네트워크 환경이었는지 아니었는지도 궁금합니다..

답글 달기