본문 바로가기
포스코x코딩온

[포스코x코딩온] 풀스택 부트캠프 16주차 정리 3차 프로젝트 회고 完

by 김선지 2024. 2. 6.

02/03

버그가 발생했다.

프론트 단에서 좋아요를 하는 백엔드는 제대로 호출이 되는데 프론트 단에 반영이 안된다는 의견이 있었다.

api는 제대로 호출이 되는데 거기서 state를 적용하지 않으신 것이었다. 그래서 state를 연결하려고 했는데 한 가지 의문이 들었다. 일반적으로 부모요소에서 data를 받고 state를 설정해서 거기다가 넣음과 동시에, setState 함수까지 props로 보내는 것이 일반적이라고 알고 있는데 과연 그냥 props로 변수만 받고 그 아래 컴포넌트에서 state를 설정하면 안될까?

라는 생각이었는데 그냥 된다. 생각해보면 당연한 거였다. 그래서 state를 적용해서 버그를 해결했다.

 

또한 post에 성별 정보도 들어가야 하는 거였는데 아무래도 post API는 좀 짜놓은지 오래 되서 그때는 성별이 들어가지 않는다는 생각으로 짰기 때문에 그냥 findAll로 데이터베이스 조회할 때 성별 또한 attributes에 넣어줌으로서 해결할 수 있었다.

또 버그가 하나 생겼다. 팀원분이 로직을 짜다가 발견하신 거였는데 갑자기 1:1 채팅에서 에러가 뜬다는 것이었다.

그게 하필이면 틀린 맞춤법을 고쳐주는 로직을 구현하다가 발견한 거라서 어디에서 에러가 뜨는지를 확인할 수가 없었다.

하지만 자세히 살펴보니 1:1 채팅에서 같은 유저의 채팅방이 두개가 생겨있음을 확인할 수 있었다.

이 것을 해결하면 오류가 자동으로 해결될 거라고 생각했다.

 

나는 1:1 채팅방을 만들 때 만약에 userid와 useridTo가 같은 Room 테이블의 데이터가 있는지 유효성 검사를 일차적으로 하고 만일 데이터가 없다면 room을 만들게 로직을 짜놨었다.

하지만 이러한 방식이라면 아래와 같이 userid와 useridTo가 같은 순서라면 알아서 room으로 navigate를 해주겠지만

userid와 useridTo의 순서가 바뀌어있다면??? => 새로운 룸을 만들 것이다.

이렇게 설정했기 때문에 userid와 useridTo가 뒤바뀌면 새로운 room을 생선하는 거였다.

 

room table

 

내가 안일했다. 당연히 내가 방을 만들었다면 valid check에 걸리는 것이 맞지만, 만약 상대방이 방을 만들었다면 내 validcheck에 걸리지 않는다. 그래서 아래와 같이 로직을 하나 추가했다.

근데 지금보니까 Op 연산자를 활용해서 or로 걸어주면 굳이 validCheck라는 변수를 두개 만들어서 걸 필요가 없었다.

뭐 처음 만들었을때 이미 validCheck으로 만들어서 추가한 셈 치자.

 

추가로 에러 페이지도 만들었다.

어차피 커스텀 훅은 그대로 있으니까 거기서 렌더해주는 페이지만 수정했다.

 


02/04

이제 서버에 배포하려고 aws에다가 데이터를 넣었다. 그래서 pm2로 실행을 하려 했는데 생각해보니까 pm2에서는 리액트의 npm start를 이용할 수 없다는 사실을 깨달았다. 뭐 서버 두개 돌리자고 했기 때문에 해당 포스트를 찾아서 해보았다.

 

이렇게 하면 build를 하고 난 이후 독자적인 포트로 돌릴 수 있다고 한다. 그렇게 되면 3000 포트와 4000포트를 동시에 돌리게 되는거고, 저번에 했던 것처럼 백 서버에서 빌드 완료 된 index.html 파일을 sendFile을 해주게 된다면 4000포트에서만 돌아갈 수 있게 되는거다. 

https://velog.io/@pp2lycee/pm2%EC%99%80-serve%EB%A1%9C-%EB%AC%B4%EC%A4%91%EB%8B%A8-%EC%84%9C%EB%B9%84%EC%8A%A4%ED%95%98%EA%B8%B0

 

velog

 

velog.io

 

근데 프론트에서 npm install 부터 문제가 발생했다.

자꾸 서버가 먹통이 되어버리는 거였다. 저번 프로젝트 때도 이런 문제가 발생했고, 재시도 했을 때 성공했기 때문에 위 문제의 원인을 내 인스턴스 탓이라고 생각했었는데, 이번에는 7번 연속으로 먹통이 되는 문제가 발생했다.

이건 다른 사람도 겪어봤을 거라고 생각했기 때문에 바로 구글링을 하니까

aws 프리티어는 1gb 램의 메모리를 이용하기 때문에 속도가 굉장히 느리고 freezing이 된다는 사실을 바로 알 수 있었다. 그래서 다음 포스트를 참조해서 해당 에러를 해결할 수 있었다.

https://dundung.tistory.com/284

 

AWS EC2 npm build 퍼센트 안 넘어갈 때, 멈출 때

EC2에서 npm build를 하다 보면 18%, 25%쯤에서 멈춰버릴 때가 있다. Building for production... 이 계속 떠 있으면서.. 처음엔 EC2가 많이 느리구나~ 하하! 하면서 기다렸는데 20분 30분이 지나도 안 끝나서 멈

dundung.tistory.com

 

근데 더 중요한게 생겼다. 이제는 용량이 부족하다. 처음 인스턴스를 만들면 8gb로 디스크를 할당해주는데 디스크를 ram으로 임시 사용까지 하고 나니까 용량이 꽉차버렸다. 그래서 구글링을 해보니 프리티어는 30gb까지 용량 사용이 가능하다고 한다. 그래서 20gb로 용량을 올렸다.

근데 적용이 안된다. 왜이러지... 했다가 인스턴스 재부팅을 깜빡했다는 사실을 깨달았다.

설정 변경은 무조건 껐다 키자...

 

이후에도 오류와의 전쟁이었다.

그렇게 해서 프론트 build까지 성공하고 서버측은 그냥 ts파일로 이용하려고 pm2 start app.ts를 해봤는데 바로 오류가 발생했다.

생각해보니까 pm2는 node.js용이지 typescript용이 아니라는 생각이 들었다.

이를 해결하기 위해 구글링을 해서 pm2 install typescript를 통해서 타입스크립트 컴파일 툴을 설치하고 하니까, 작동이 되긴 했지만 10초 후에 자꾸 list에서 error가 발생함을 알 수 있었다.

 

이게 대체 무슨 에러지... 하다가 에러 로그를 찍어보기 위해 pm2 에러로그를 찍어보니까 type들이 설치되어 있지 않다는 콘솔을 확인할 수 있었다. 아마도 default로 설치되어야 하는 건데 ec2에서는 그걸 못해주는건가 싶어서

npm install @types/something 을 통해서 해당 에러를 잡을 수 있었다.

이렇게 된 김에 서버의 app.ts도 빌드 해서 쓰자고 생각했다.

하지만 이제는 다른 에러가 발생했다.

ts-node app.ts를 할 때 로컬에서는 "esModuleInterop": true 속성을 통해서 그냥 되었는데

build를 es5 -> commonJS로 변환하기 때문에 import라는 속성을 읽지 못한다는 것이었다. 다행히도 이 에러는 프로젝트 시작할 때 많이 겪었던 에러였다.

디폴트 호출을 할 때는 import * as something from "something"으로 해주면 된다. 다만 이 호출한 something을 함수로 이용하면 이야기가 달라진다. 그리고 그를 위한 exModuleInterop: true였다.

근데 이 속성도 빌드할 때는 못받는 것 같으니 그냥 commonjs 문법을 쓰는 게 정신건강에 이로울 것 같았다.

그래서 express 같은 함수로 호출해야 하거나 default 값을 import 해야하는 것은 import가 아닌 require를 이용해서 빌드할 수 있었다.

다만 이렇게 하니까 갑자기 잘 보이던 사진들이 어떤 것은 나오고 어떤 것은 나오지 않는다.

... cors 에러인가..? 라고 생각하고 이것저것 뜯어보던 중, 대문자 소문자 구분이 아닐까하는 생각이 들었고 이게 적중했다.

local에서는 알아서 구분해주는 것 같은데 서버 단에서는 완벽하게 대소문자까지 일치해야 경로를 찾는다는 사실을 알게 되었다. (뭐 후자가 당연한 거기는 하다.)

약간 로컬은 인자한데 약간 만만한 사람같으면 후자는 완전 fm이다. 마치 js와 ts의 차이랄까.

 

에러를 해결하다가 그냥 sendfile로 해결했기에 내 pm2에는 app.js에만 실행되게 하면  된다.

 


02/05

 

경로 수정에 성공했다.

로컬에서는 프록시로 설정해놨기 때문에 포트번호도 넣어주지 않았지만 올리니까 이젠 "SERVERURL/getsome" "CLIENTURL/get" 이런식으로 path 설정을 해줘야함을 알게 되었다. axios의 url도 img path도 마찬가지다.

 

그리고 배포를 하고 나서 포트를 따로 설정을 안하고 들어가니 저번에 죽였던 아파치2가 다시 부활했다. 대체 나한테 왜이러는지 모르겠다. 그래서 리더님께 가서 도움을 요청했다. 내 코드를 보고 하시는 말이 nginx는 따로 포트 두개를 실행하지 않고 서버만 실행해도 알아서 리액트 파일을 인식해서 보여주고, sendFile()을 해서 서버 url로 접근할 필요도 없고,

80번 포트로 접근하면 알아서 react를 띄워주고, 4000번 포트에서 일어나는 일을 보여줄 수 있다고 하셨다. (리버스 프록시)

내가 했던 pm2 serve build 3000를 안해도 된다는 뜻이다. 물론 4000번 서버는 열어야 한다.

근데 그렇게 하기 위해서는 react용 nginx 설정을 따로 해야 한다고 하셔서 도움을 받는데 계속 nginx를 재시작 할 때 에러가 뜸을 확인할 수 있었다.

그럴땐? chat gpt.

 

아... 그놈의 아파치... 

결국 리더님의 도움을 받아서 드디어 아파치를 종료할 수 있었다. 톰캣... 이젠 보지 말자

그렇게 아파치를 종료하고 nginx를 실행하니 이제 80번 포트에서 아파치가 동작함을 알 수 있었다.

그렇게 서버를 여니까 갑자기 cors에러가 엄청나게 뜸을 확인할 수 있었다.

그렇게 요청 origin을 보니까 (내 ip주소)가 요청을 함을 알 수 있었다. 지금까지는 

 

다음 이미지와 같이 유알엘 하나만 설정했는데, 내 아이피 주소:80도 포함시켜야 했다. 그런데도 코스에러가 계속 뜸을 확인할 수 있었다. 알고보니까 :80도 빼고 그대로 적어야 함을 알 수 있었다.

 

하지만 [] 배열로 여러개의 오리진을 두는 것도 코스 자체에서만 가능하지 socket의 cors에서 [배열url]을 넣는 것은 불가능한 문법임을 확인할 수 있었다. 그러니까 socket에서는 하나의 origin만 받도록 하자.

 

 

다만 갑자기 오류가 발생했는데 이전 페이지로 navigate를 해줄 때 내가 설정했었던 beforeunload 이벤트가 발생하지 않는다는 사실을 알게 되었다.

당연히 배포 ec2에 올렸을 때 안되는 거니까 배포측에 오류가 있는 거라고 생각했다. 근데 배포 주소에서 localhost로 그대로 바꾼 로컬에서도 적용되지 않는 것을 확인했다. 이것도 아까와 마찬가지로 로컬에서는 proxy로 잘 했기 때문에 알아서 의도대로 결과를 가져오는 거였다.

그렇게 된다면 navigate의 문제이리라.

 

이럴땐? chat gpt다

결과적으로 navigate 함수는 내가 의도한 결과를 발생할 수 없었다.

뒤로가기와는 다르게 완벽히 새로운 redirect를 할 거라고 생각했던 navigate는 로컬에서는 성공했었지만. 이건 proxy가 가져다준 허상이었던 것이다.

그렇기 때문에 window.location.href를 이용해서 해야만 했고, 다만 한가지 고려할 점이 navigate(-1)을 이용했었기 때문에 가능했던 건데, 이렇게 되면 유동적으로 주소값을 가져가지 못하고 하드코딩을 해야한다.

근데 한 가지 특이사항이 있었다. 컴포넌트를 모노챗과 개인챗 둘 다 쓴다는 것이다. 그래서 다음과 같이 해결할 수 있었다.

 

 그 후로 배포 서버를 보면서 경로가 이상한 것들을 확인할 수 있었고 잡을 수 있었다.

 


02/ 06

 

그 후로 나타난 에러들을 수정했다. 대부분의 에러는 경로 에러였기 때문에 큰 문제가 없었지만, 다음 에러때문에 골머리를 앓았다.

 

이 에러였다.

처음에는 왜 undefined가 뜨는지를 몰라서 그냥 내가 경로를 잘못 설정했다고 생각했다.

하지만 계속 드릴링을 해서 찾아보니까 이 undefined로 된 값은 props로 전달되고 있다는 사실을 확인할 수 있었다.

그렇게 점점 파고들어가서 이유를 찾을 수 있었다.

처음에 useEffect를 활용해서 받아오는 값들이 있는데 여기 url의 params 값에 props에서 받아온 값을 이용한다.

하지만 그때 props는 아직 받아오지 못해서 undefined된 상태이고. 이를 통해서 4000/userinfo/undefined라는 괴상한 경로가 생기고 이건 useEffect로 실행되기 때문에 axois 404에러가 발생하는 거다.

이건 setTimeOut같은 생각나는 방법을 써봤는데 해결할 수 없었다. 아무래도 props도 state와 비슷한 개념이라서 한꺼번에 batch가 되는 것이 원인인 것 같다.

그러다가 든 생각인데 이걸 props로 받아오지 않고 다른 방법으로 받아오면 된다는 생각이 들었다.

이게 아니었다. 이 에러가 뜬 이유는 이게 맞는데. 다시 fetch를 해오기 때문에 해당 구문은 잘 동작한다.

애초에 이건 post와 댓글 유저의 이름과 성별, 프로필 사진을 가져오기 위해서 있는 api고 잘 가져오니까 props가 다시 와지면 다시 한번 fetch 요청을 보내고 성공한다.

 

게다가 이거 때문에 delete comment가 안된다고 생각했는데 이 포스트를 쓰면서 생각해보니까 아니었다. 왜 포스트 수정 로직 당일에 고쳐놓고 댓글은 다른 것이 원인일거라 생각했을까...? 이것도 경로문제다...

 

+ 이것도 내가 post 수정하면서 같이 수정했기 때문에 적용된다...

 이사람들 새로고침 안해놓고 나한테 에러있다고 한거였네.... 혼좀 나야겠다.

 

+ 포스트 detail 페이지에서 연필 버튼을 눌러서 글 첨삭을 해주면 현재 navigate(-1)로 되어있기 때문에 새로 redirect하는 것이 아니라 뒤로가지기 때문에 새로 렌더링이 안되는 걸 오류라고 생각했던 것 같다. 이건 경로에 조건을 걸어서 window.location.href 속성을 이용해서 해야할 것 같다.

 

피드백 받았는데 뭔가 건설적이라서 좋았다. 확실히 면접관 입장에서 생각하고 유저 입장에서 생각하면서 만들어보자.

 

어쨌건 3차 프로젝트도 무사히 종료되었다. 이번엔 진짜 갈린거같은데 리더님한테 기능 많다고 칭찬 들어서 기분이 좋다.