1. 어려웠던 부분: 오늘도 역시나 원인을 명확히 알 수 없는 CORS에러와 https 관련 에러로 골머리를 앓았다. 아무리 에러 메세지를 구글링해보고 이방법 저방법 따라해봐도 잘 해결이 되지 않는다. 결국 배포를 맡은 팀원이 다시 도메인을 파고 배포하는 과정을 반복하기까지 했는데도 해결되지 않았다. http 에서 https로 바꿨을 뿐인데 발생하는 에러가 너무많다. 아부지 정답을 알려죠 .... 내일 있는 기술 멘토링에서 해답을 얻기를 ! 아래는 내일 여쭤볼 질문 사항들이다.
2. 느낀 점 : 오늘 오랜만에 디자이너님과 디자인 회의를 했다. 오랜만에 숨통트이는 시간이었다. 너무 우리가 원하고 생각한 대로 작업을 잘 해주셔서 감사했다. 디자이너님도 국비로 스프링을 배우고 개발일을 하시다가 UX디자인 쪽으로 전향하셨다고 했는데, 진짜 능력자이신 것 같다. 나도 훗날 기회가 된다면 프론트엔드나 디자인 쪽도 공부해보고 싶다는 생각이 들었다.
3. 새로 알게 된 내용: https로 배포를 할 때 인증서를 발급하는데, 인증서 해당 도메인을 프론트엔드 주소와 백엔드 주소 모두 (2개) 넣어줘야 한다. 그렇지 않으면 계속해서 아래 참조링크와 같은 에러가 발생한다.
4. 셀프칭찬 (오늘 잘한 일): 하루 종일 에러와의 싸움... 해결된건 거의 없지만 잘 버텼다.
웹 브라우저 클라이언트로부터 HTTP 요청을 받아들이고 HTML 문서와 같은 웹페이지를 반환하는 컴퓨터 프로그램
클라이언트가 웹 브라우저에 어떠한 페이지 요청을 하면 웹 서버에서 그 요청을 받아 정적 컨텐츠를 제공하는 서버
정적 컨텐츠란 HTML, CSS, JavaScript, 이미지, 파일 등 즉시 응답 가능한 컨텐츠를 의미한다.
웹 서버가 동적 컨텐츠 요청을 받는 경우, WAS에게 해당 요청을 넘겨주고 WAS에서 처리한 결과를 다시 클라이언트에게 전달해주는 역할을 한다.
대표적인 웹 서버엔 Apache 가 있다.
WAS
인터넷 상에서 HTTP 프로토콜을 통해 사용자 컴퓨터나 장치에 애플리케이션을 수행하주는 미들웨어이다
주로 동적 서버 컨텐츠를 수행하는 것으로 웹 서버와 구별이 되며, 주로 데이터 베이서 서버와 같이 수행한다.
WAS는 웹 서버와 웹 컨테이너가 합쳐진 형태로, 웹 서버 단독으로는 처리할 수 없는 데이터베이스의 조회나 다양한 로직 처리가 필요한 동적 컨텐츠(JSP, ASP, PHP)를 제공한다.
덕분에 사용자의 다양한 요구에 맞춰 웹 서비스를 제공할 수 있다.
WAS는 JSP, Sevlet 구동환경을 제공해주기 때문에 웹 컨테이너 혹은 서블릿 컨테이너라고도 불린다.
대표적인 WAS 종류엔 Tomcat이 있다.
Wev Service Architecture
웹 어플리케이션은 요청 처리 방식에 따라 다양한 구조를 가질 수 있다.
클라이언트(사용자) -> WebServer -> DB
클라이언트 -> WAS -> DB
클라이언트 -> WebServer -> WAS -> DB
WebServer 와 WAS를 나누는 이유
이론대로라면 WAS의 경우 웹서버 + 웹컨테이너의 개념이기 때문에 웹서버가 없더라도 웹서버의 역할을 동시에 수행할 수 있다.
그런데 왜 나눠서 사용할까?
1 데이터 처리 방식
위의 설명대로 웹서버는 정적 컨텐츠를, WAS는 동적 컨텐츠를 처리한다.
만약 부하가 적은 웹서비스라면 두가지 요청을 WAS 하나로 다 처리해도 되지만, 부하가 많다면 빠른 시간에 처리할 수 있는 정적컨텐츠를 WAS에서 처리하는 것은 비효율적이다.
웹서버를 WAS 앞에 두고 필요한 WAS들을 WebServer에 플러그인 형태로 설정하면 더 효율적인 분산처리가 가능하다.
2. 보안상의 이유
사용자들에게 WAS는 공개될 필요가 없다.
WAS의 경우 DB서버에 대한 접속 정보가 있기때문에 외부로 노출될 경우 보안상 문제가 될 수 있다.
이러한 이유로 웹 서버의 경우 DMZ구간에 위치하고 WAS는 내부망에 위치시켜 보안을 유지할 수 있다.
Tomcat vs Apache Tomcat
위에서 언급한 대로 웹 서버의 대표는 Apache, WAS의 대표는 Tomcat이 있다.
Tomcat은 Apache Tomcat 이라는 이름으로 많이 사용되는데, 이유는 Tomcat5.5 버전부터 정적 컨텐츠를 처리하는 기능이 추가되어 이 기능이 순수 Apache를 사용하는 것에 비해 성능적 차이가 거의 없으며 Tomcat이 Apache의 기능을 포함하고 있기 때문이다.
Front와 협업중에 구매한 도메인을 적용했고 서버에서 데이터를 문제없이 내려주기 위해서 CORS에 해당 도메인을 등록했다. 해당 도메인을 등록하고 나니까 localhost:3000 [즉, 프론트쪽 리액트 local] 에서 spring 서버로 접근이 안되는 현상이 발생했다.
문제 발생했을 때 코드
수정된 코드
allowedOrigins 대신 allowOriginPatterns를 사용
일단 이렇게 해서 해결이 되긴 했는데, 이 글을 쓰면서 관련 에러를 더 찾아보니 새로운 사실을 알게 되었다.
원인 / 해결 방법 (추측임 , 확실하지 x)
(어느블로그에서 본 글이기 때문에 정확한 정보라고 볼 순 없을 것 같다.)
AllowedOrigins()은 중복해서 사용할 수 없다. 중복할 경우 값이 계속해서 덮어씌여지면서 앞에 Setting 값들이 다 날아간다.
즉, 올바른 사용은 다음과 같다.
.setAllowedOrigins("http://localhost:3000", "http://--------.cloudfront.net") 으로 사용하거나
.setAllowedOrigins("*")를 사용해준다.
-----> 수정 !!
.setAllowedOrigins("http://localhost:3000", "http://--------.cloudfront.net") 으로 사용해도 에러가 난다.
A list of origins for which cross-origin requests are allowed where each value may be one of the following:
a specific domain, e.g."https://domain1.com"
comma-delimited list of specific domains, e.g."https://a1.com,https://a2.com"; this is convenient when a value is resolved through a property placeholder, e.g."${origin}"; note that such placeholders must be resolved externally.
the CORS defined special value"*"for all origins
For matched pre-flight and actual requests theAccess-Control-Allow-Originresponse header is set either to the matched domain value or to"*". Keep in mind however that the CORS spec does not allow "*" when allowCredentials is set to true and as of 5.3 that combination is rejected in favor of using allowedOriginPatterns instead.
By default this is not set which means that no origins are allowed. However, an instance of this class is often initialized further, e.g. for@CrossOrigin, viaapplyPermitDefaultValues().
https://*.domain1.com -- domains ending with domain1.com
https://*.domain1.com:[8080,8081] -- domains ending with domain1.com on port 8080 or port 8081
https://*.domain1.com:[*] -- domains ending with domain1.com on any port, including the default port
comma-delimited list of patters, e.g."https://*.a1.com,https://*.a2.com"; this is convenient when a value is resolved through a property placeholder, e.g."${origin}"; note that such placeholders must be resolved externally.
In contrast toallowedOriginswhich only supports "*" and cannot be used withallowCredentials, when an allowedOriginPattern is matched, theAccess-Control-Allow-Originresponse header is set to the matched origin and not to"*"nor to the pattern. Therefore, allowedOriginPatterns can be used in combination withsetAllowCredentials(java.lang.Boolean)set totrue.
By default this is not set.
Since:5.3
정리
스프링부트 5.3부터 allowCredentials가 true일 때 allowedOrigins에 특수 값인 "*" 추가할 수 없게 되었다. 대신 allowOriginPatterns를 사용해야 한다.
근데 이 이유때문에 발생한 오류는 아니었을 것 같다는 느낌 ... 아시는분 댓글 부탁드립니다 !
1. 어려웠던 부분: 오늘 https 서버를 배포하고 WebRTC 시그널링이 연결은 됐는데, 게임방나가기 로직에서 문제가 생겼다. 방을 나가도 연결이 제대로 끊기지 않아 남아있는 사람들에게 나간사람의 화면이 계속 보이는 에러가 있었다. 그리고 서버를 https로 바꾼 이후 계속해서 NET::ERR_CERT_COMMON_NAME_INVALID 라는 에러 혹은 403에러가 발생했다. 오늘 해결하진 못했는데 아마 추측하기론 https로 보안 단계를 올리면서 뭔가 안맞아서 발생하는 에러인 것 같다.
2. 느낀 점 : 하나가 해결되면 다른 하나가 터지는 개발의 세계. 그나마 다행인 것은 왠만한 에러들은 구글링을 통해 해결할 수 있다는 것이다. 그런데 구글링을 해도 해결되지 않는 오류는 어떻게 해결해야 할까 ? 구글링을 더 더 더 잘하는 방법이 뭐가 있을까. 요즘 터지는 에러들은 구글 페이지 끝까지 글을 뒤져보고 공식 문서를 찾아봐도 잘 해결이 되지 않는다. 이럴 땐 어떻게 해야하는지, 현업에선 어떻게 해결하는지 궁금하다.
3. 새로 알게 된 내용: 어제 새롭게 구현한 Redis Token 에 대해 공부했다. 왜 사용하는지, 어떤 한계점이 있는지 그리고 어디에 저장하는게 옳은 것인지 등등 다양한 글을 찾아봤는데, 글마다 토큰을 저장하는 위치가 달라서 많이 혼란스럽다. 일단 구현된 코드는 Redis 스토리지에 저장하는 방식이긴 한데 이 부분을 좀 더 연구해 봐야곘다.
4. 셀프칭찬 (오늘 잘한 일): 나의 시간이 비었을 때 다른 팀원의 에러를 같이 해결하거나 추가적인 공부를 하는 나 자신을 칭찬하려고 한다. 나는 내 방식대로 열심히 공부하고 풀어지지 않도록 노력중이다.