프론트엔드(리액트)와 백엔드(스프링)을 연동하는 과정에서 아래와 같은 에러가 났다.
나는 스프링을 이용해 백엔드 서버를 하고 있고, 친구가 리액트를 이용해 프론트엔드를 맡고 있다.
로컬 환경에서 postman을 이용해 응답 테스트를 할 때는 잘 돌아갔다.
AWS에서 서버를 만들어서 톰캣서버를 만들고 프로젝트를 올려 postman을 이용해 응답 테스트를 할 때도 잘 돌아갔다.
크롬에 새 창을 켜서 url로 get요청을 보내면 잘 작동한다.
그러나!!!
근데 리액트랑 연동만 하니 CROS 에러가 나타났다.
CORS란? Cross-Origin Resource Sharing(교차 출처 리소스 공유)의 약자이다.
정확히 CORS가 뭔지는, 프로젝트가 끝난 후 시간이 생겼을때 공부해서 포스팅을 하도록 하겠다.(추후를 기약)
위의 에러를 보면 CORS 정책에 의해서 요청이 막혔고, 'Access-Control-Allow-Origin' 헤더가 요청 리소스에 없다고 나온다.
9월 1일 목요일
구글링을 해보니 CORS... 진짜 골치아픈 놈 같다.
일단 인터넷에 나온방법 세개 써봤는데 안된다.
다음주에 다시 도전한다!
일단 쓴 방법
1. @CrossOrigin 어노테이션 사용 -> cros 에러는 발생하지 않으나 쿠키가 프론트로 전달이 안되는 듯 하다.
2. WebMVCConfigurer -> net:error_failed
3. filter로 헤더 세팅하기 -> net:error_failed
*모든 과정에서, 프론트에서는 withCredential 옵션을 true로 설정해줬다.
9월 2일 금요일
구글링하다가 다른 형태의 filter를 찾아서 적용을 해봤는데 잘 되어서 해결방법을 소개한다.
해결방법: https://sangjin0309.tistory.com/10 에서 발견한 코드를 토대로 약간의 수정을 하여 아래와 같은 새로운 코드를 추가하였다. CorsFilter.java라는 새로운 파일을 만들어서 아래의 코드를 붙여넣어 준다.
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse;
public class CorsFilter implements Filter {
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) res;
response.setHeader("Access-Control-Allow-Origin", "http://localhost:3000");
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTION");
response.setHeader("Access-Control-Allow-Credentials", "true");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "x-requested-with, origin, content-type, accept");
chain.doFilter(req, res);
}
public void init(FilterConfig filterConfig) {}
public void destroy() {}
}
위의 코드에서 중요한 것은,
"Access-Control-Allow-Origin"를 "http://localhost:3000"로 셋팅하는 것
-> 바로 아랫 줄의 withCredential : true 옵션을 쓰려면 *로 쓰지말고 주소를 특정해줘야 한단다
"Access-Control-Allow-Credentials"를 "true"로 셋팅하는 것
-> 백과 프론트 양쪽에 설정해야 쿠키를 주고 받을 수 있단다
"Access-Control-Allow-Methods"에 사용하는 http 메소드와 OPTION 메소드를 추가하는 것
-> preflight인지 뭔지 하는 과정에서 OPTION 메소드를 이용해 확인한단다
추가로 web.xml 파일에 아래와 같은 필터도 넣어준다.
<filter>
<filter-name>CorsFilter</filter-name>
<filter-class>{패키지 경로}.CorsFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>CorsFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
CORS 에러는 해결!
그러나 또 다른 난관이 있었으니...
바로 프론트 쪽에서 쿠키를 받고 이를 저장할 수 있었으나, 이 쿠키가 다음 요청에서 백엔드로 다시 보내내지가 않았다!!!
이날, 프론트를 맡은 친구와 6시간의 삽질을 하고 알게 된 바는, 바로 크롬 정책중에 samesite 정책 때문이란다.
크롬의 SameSite = lax 라는 값 때문에 교차 출처로 쿠키가 전송이 안되는 것이었다.
이를 해결하려면 옵션을 변경하기도 해야하고, http://를 https://로 바꿔야 하는데, 이 과정에서 인증서도 발급받고... 아무튼 뭐가 되게 복잡해 보였다...
그래서 우리는 결국,
프론트에서 Proxy를 쓰기로 하였다^^
프록시 서버는 구글링하면 나오는 CORS 이슈를 해결하는 방법 중 하나이다.
프록시 서버란? 클라이언트에서 서버로 접속을 할 때, 직접적으로 접속하지 않고 중간에 대신 전달해주는 서버이다.
프록시 서버에 대해서도 나중에 시간나면 차차 포스팅 해보겠다^^
아무튼 이 서버를 백엔드 서버주소와 같게 하였더니 해결!
그럼에도 불구하고 아직 해결되지 않은 문제가 있었는데,
프록시 서버를 썼음에도 404에러가 나는 것. 분명히 맞는 url로 요청을 보냈는데 이상하다.
그래서 둘이 잠들기 직전까지 또 삽질을 했는데, 프론트 친구가 구글링해서 다음 내용을 봤다고 했다.
간단히 말하면,
프록시 서버를 설정하는 과정에서 내가 모든 요청 url을 http://{서버주소}:8080/api/~ 로 시작할 수 있게 @RequestMapping(value="/api")를 모든 controller 클래스의 제일 위에 달아주었는데,
/api로 시작하지 않는 경로에 대한 처리가 없을 경우 404 에러가 뜨기도 한다는 내용이다.
아무튼, 나는 프로젝트에 http://{서버주소}:8080/ 으로 get요청이 들어왔을때 간단한 응답을 반환하는 코드를 작성해서 해결봤다.
야호!!!😂😁😂😁😂😁😂😁😂
'개발 노트 > 에러 화풀이 기록' 카테고리의 다른 글
ECS fargate 환경에서 FCM에 쓸 service-account.json 설정하기 (1) | 2024.11.07 |
---|---|
왜 테이블 생성은 잘 되는데, 외래 키 추가는 무한로딩이죠? (1) | 2024.10.07 |
[Spring] java.sql.sqlexception 소켓에서 읽을 데이터가 없습니다 에러 / c3p0, commons dbcp2 커넥션풀 사용 (0) | 2022.09.01 |