인생은 회전목마 우린 매일 달려가

언제쯤 끝날진 잘 몰라

Project

[아이젠하워 매트릭스] 바닐라JS 배포 시 만났던 에러

안심심한 아샤 2023. 8. 17. 03:35

1. [DEP0018] await 에러 처리 문제

(node:251698) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

await 한 곳에 에러 처리를 안해서 생기는 문제였다.

해결법 : try catch로 다 에러 처리해주기

 

사실 처음에는

'엥?! 나 에러 처리 했는데!!'

했지만 몇 군데가 처리가 안되어있었다...

이런 곳들...

여기두..

그 외에도 에러 처리를 안해준 곳들이 많아서 다 처리해주고..

확인해보니 백엔드는 다 에러처리를 했었는데 프론트가 안된 곳들이 많았다.

조금 더 신경 쓰는 걸루..

 

2. 디비 에러라기엔 경고(1) - secret에서 db 정보 불러올 때

const mysql = require('mysql2/promise')
const dbSecret = require('./secret') 

exports.pool = mysql.createPool(dbSecret)

db 연결할때 바로 db 정보를 노출 시키면 보안상의 문제가 발생하기 때문에

secret.js 파일에 디비 정보를 써놓고 불러오는 방식으로 작성했었다.

근데 계속 이런 에러가 떠서 구글링을 해보니 버전이 달라서 그런다 이런 해결방법이 아닌 것들만 나와서 난감했다,, 만

결국 우리의 친구 chat gpt에게 물어보고 몇 번의 질의를 거쳐서

const { dbSecret } = require('./secret);

exports.pool = mysql.createPool({
  host: dbSecret.host,
  user: dbSecret.user,
  port: dbSecret.port,
  password: dbSecret.password,
  database: dbSecret.database,
});

이런 방식을 고안해내었고

결과는 

깔끔하게 해결!!!

 

3. 디비 에러(2) - 회원가입 시 브라우저는 잘 뜨지만 디비에 들어가지 않음

찾아보니 에러 처리 부분들이 console.log(error( ~~~~)) 이렇게 쓰여져 있었다.....

후...ㅠㅠ그래서 다 console.log로 바꿔주고<<<는 error를 권장한다고 나와있어서 console.error로 다시 바꿔주었다.>>>

필요없는 console들은 지워주고

무중단 배포 pm2 재시작...

다시 회원가입 확인해보니

회원가입은 디비에 잘 들어오고 잘 동작했다

 

4. 디비 에러(3) - 로그인 시 브라우저에서 반응이 안오다가 한참 뒤에 504 Gateway Time-out 발생

로그인 시 브라우저 반응이 없어서

'뭐지 프론트에서 뭔가 잘못했나?'

하고 찾아보는데 아무리 봐도 무결... 다시 브라우저를 확인해보니 한참 뒤에 이런 에러가 발생했다.

이것은 필시 백엔드 문제이다. 역시 모든 문제는 백엔드에서 나온다

router - controller - database 이렇게 파일이 구성되어 있기 때문에 라우터 부터 살펴보는데..

const { jwtMiddleware } = require('../../jwtMiddleware')
const userController = require('../controller/userController.js')

exports.userRouter = (app) => {
  // 회원가입 API
  app.post('/user', userController.signup)

  // 로그인 API
  app.post('/signin', userController.signin)

  // jwt 검증 API
  app.get('/jwt', jwtMiddleware, userController.getNickname)
}

사실 router 파일에는 이렇게 심플하게 해놔서 뭐 문제가 될게 없었다

controller로 고고 해서

const { email, password } = req.body

  if (!email || !password) {
    return res.send({
      isSuccess: false,
      code: 400,
      message: '회원정보를 입력해주세요.',
    })
  }

  // 회원여부 검사
  const isValidUser = await userDatabase.selectUser(email, password)
  if (!isValidUser) {
    return res.send({
      isSuccess: false,
      code: 410,
      message: 'DB 에러, 담당자에게 문의해주세요.',
    })
  }
  if (isValidUser.length < 1) {
    return res.send({
      isSuccess: false,
      code: 400,
      message: '존재하지 않는 회원입니다..',
    })
  }

이 부분들에 email, password, isValidUser 모두 콘솔을 찍어보는데 

아무것도,,,, 반응하지,,, 않는다,,,,,,, 제발,,, 살려줘.....

저 코드 외에는 jwt 발급, 연결 부분인데 우선 디비부터 뜯어보기로 하고 디비 파일을 살핀다.

exports.selectUser = async function (email, password) {
  try {
    const connection = await pool.getConnection(async (conn) => conn);

    try {
      const selectUserQuery =
        "select * from Users where email = ? and password = ?";
      const selectUserParams = [email, password];

      const [row] = await connection.query(selectUserQuery, selectUserParams);
      connection.release();
      return row;
    } catch (err) {
      console.error(` ##### selectUser Query error ##### `);
      connection.release();
      return false;
    }
  } catch (err) {
    console.error(` ##### selectUser DB error #####`);
    return false;
  }
};

우선 내가 지금 풀스택으로 프로젝트를 만들어 보고 있지만 후론트전문이지 백엔드 전문이 아니기 때문에..

mysql2에 대한 것부터 찬찬히 뜯어봤다. mysql2는 prepared statements를 지원하기 때문에 query말고 execute를 사용할 수 있고, 시간을 조금이라도 단축시킬 수 있기 때문에 query 부분들을 다 execute로 바꿨다.(execute는 내부적으로 prepare와 query를 호출한다.)

물론 해결은 안됐고.. timeout이 뜨는 다른 사람들을 찾아보니 pool connect후 release를 안해줘서 과부하가 걸렸던데..

보다시피 나는 이미 release를 하고 있는 상태다...

exports.selectUser = async (email, password) => {
  // DB 연결 검사
  try {
    const connection = await pool.getConnection(async (conn) => conn)

    // insert query
    try {
      const selectUserQuery = 'select * from Users where email = ? and password = ?;'
      const selectUserParams = [email, password]

      const [row] = await connection.execute(selectUserQuery, selectUserParams)
      return row
    } catch (err) {
      console.error(` ##### selectUser DB error ##### \n ${err}`)
      return false
    } finally {
      // db 과부화 되지 않게 연결 다시 끊어주기
      connection.release()
    }
  } catch (err) {
    console.error(` ##### selectUser DB error ##### \n ${err}`)
    return false
  }
}

최종적으로 바꾼 부분 connection.query -> connection.execute기존에 try catch마다 일일이 썼던 connection.release() 를 finally로 처리해줌

 

하지만 결국 문제는 디비가 아니었다... 문제는 바로바로..controller의 signin에서 await 부분에 try catch 를 쓰는데ㅎ... 인생은.. 언제나 허무한 것....

// jwt 토큰 발급
  const [userInfo] = isValidUser
  const userIdx = userInfo.userIdx

  const token = jwt.sign({ userIdx }, jwtSecret)

  return res.send({
    result: { token: token },
    isSuccess: true,
    code: 200,
    message: '로그인 성공',
  })

이 부분이 try catch문 바깥으로 빠져있었다... 그러니... 그러니 토큰 인증이 아예 안먹고 isValidUser는 정의되어있지도 않고....

로그인 했을 때 ValidUser가 맞으면 바로 토큰 발급에 토큰 검증을 들어가야 되는데 걔가 없으니..........기다려도 답이 안오니.... timeout이 뜨지 하하하하하하하하하ㅏ하하하하핳핳하하하하핳하하 

원래는 적당히 하고 내일 에러 수정해야지 하다가 하다보니 오기가 생겨서 에러가 이기나 내가 이기나 보자!!1 이러고 새벽까지 안자고 하다가 이 부분을 발견하고 내 마음 속 인생 허무주의가 다시금 수면 위로 떠오르면서  좌절하려 할 때

아니야 하고 에러일지를 작성하고 자야겠다는 생각이 들어서 지금.. 이 ... 새벽 3시까지 에러 일지를 쓰고 있다.

인생.....

그래도 일하다가 이런 에러난 거 아니라서 얼마나 다행이야... 

그.리.고 아직 풀스택 개발자로 일하는 거 아니라서 다행이다^0^

풀스택이 하고 싶어서 프로젝트마다 프론트 백 둘 다 해보려고 하지만 역시 백엔드는 아직 미숙하다...아니 어쩌면 커피를 안마셔서 그런 거 아닐까...?그래도 중요한 것은!!! 모두 해결 됐다는 것!!!!

 

완성작

화면 기록 2023-08-17 오전 3.03.42.mov
18.82MB

로그인 시 엑세스 토큰 잘 들어오고, 투두 추가, 수정, 체크, 삭제 다 잘 동작,

로그아웃 시 엑세스 토큰 사라지고 투두 다 없어지고

재로그인 시에도 모두 잘 남아있음!

자세한 기능은 다음 글에..