본문 바로가기
spring & boot/Project Issue

[운영 장애 회고] TypeError: undefined is not an object 에러(JS) -#1

by lucas_owner 2024. 1. 10.

오류 발생에 대한 전체적인 흐름 및 회고.

아래 JS 문법에 대한 방법은 2-2번 항목에 존재.

TypeError: undefined is not an object (evaluating 'this.error.use = msg')

 

**환경

  1. Front: Vue2 + option API
  2. Back: Spring Boot(Rest)

 

1. 장애 상황 및 이슈

- 글 작성일 기준일 오후중 운영환경에서 발생한 장애 이슈. 

클라이언트에게 보여지면 안되는 오류얼럿 메시지가 노출되고, 사용자의 요청 결과를 출력하지 않는 이슈발생

 

- 흐름

프론트단에서의 클릭 이벤트 발생 -> 서버단에서의 각종 유효성 조회 및 검증 -> 검증통과시 http status 200 return - end

 

front 의 콜백함수에는 서버단에서 발생할 수 있는 Exception에 대한 Error Handling 이 되어있는 상태였다(catch).

그렇다면 여기서 의심할 수 있는 상황은 이렇다. 

  1. 서버단에서 발생하는 추가적인 Exception 발생.
  2. 추가된 Exception 은 없지만, 에러 핸들링에 대한 처리 미흡.
  3. 오류 얼럿 메시지에 기반한, JS 문법 오류

결론은 1,3 번 에서 발생. 

 

2. 해결 방법 

* 오류 코드 기반 재구성

2-1. Back

// Server Side 내부 로직 중 ...
if(param.equals("go")) {
            log.debug("RunTimeException !@!!!! param = {}", param);
            throw new BadRequestException(); //400
}

- 특정 결과를 기반으로, BadRequestException(400) 을 리턴. 

- 클라이언트에겐, BadRequestException이 아닌 Custom Exception을 return 했어야 했다.

 

 

2-2. vue.js

data() {
    return{
      id: 'Error Test Pages',
      result: {},
      error: {
          status: '',
          msg: '',
      }
    }
  },

// 해결 전
test() {
      axios.get('/api/error/bad', {params: {param: 'go'}})
        .then(res => {
          console.log(res);
          this.result = res.data;
        }).catch(function(error) {
            console.log('error!',error);

            // return msg
            const errorRes = error.response.data;
            console.log('error data',errorRes);
            let code = '';
            switch (errorRes.msg){
              case 'day':
                code = '런타임에러'; break;
              default:
                code = '잘못된 요청';
                break;
            }
            // 문제의 코드
            this.error.msg = code;
      });
      // axios 에는 예외처리를 하고있는 하나의 객체가 감싸고 있음.
    }

 

- 해당 부분에서 정상 결과에 대한 콜백은 arrow(화살표) 함수를 사용하여 처리했지만, catch 부분에서는 function(){} 사용.

- 오류 얼럿에서 나온 메시지와 같이 'this.error.msg = code' 해당 부분이 문제인것 확인. 

 

 

Vue2 에서 data 객체에 접근하여 사용하는 방법과 같이 this.data객체.~ 를 사용한게 원인이었다.

JS 에서는 function 객체는 자신만의 this 객체를 가지고 있다. 그렇기 때문에 

Vue 데이터 객체의 error.msg 부분에 접근을 할 수 없었던 것. (즉 function 내부에는 this.error.msg 는 Undefined 상태)

* JS에 대해서 자세히 몰랐기 때문에 빠르게 해결할 수 없었다....

 

즉, function 은 자신의 this 를 가지고 있고, 상위 객체를 바인딩 하는것이 아니라, function 객체의 this 를 바인딩. 

arrow function(화살표 함수)는 자신의 this 객체를 가지고 있지 않기 때문에, 상위 환경의 this 객체를 바인딩.

 

2-3 JS 해결코드 -1 

// 예전 방식 -> $this($that) 변수 
test() {
      let $this = this;
      axios.get('/api/error/bad', {params: {param: 'go'}})
        .then(res => {
          console.log(res);
          this.result = res.data;
        }).catch(function(error) {
            console.log('error!',error);

            // return msg
            const errorRes = error.response.data;
            console.log('error data',errorRes);
            let code = '';
            switch (errorRes.msg){
              case 'day':
                code = '런타임에러'; break;
              default:
                code = '잘못된 요청';
                break;
            }
            // 문제의 코드
            $this.error.msg = code;
      });
    }

예전 방식의 $this 방식이다. 자신만의 객체를 가지고 있는 function 밖에서 global this 객체를 가르키는 변수를 생성하는 방법이다. 

 

2-4 JS 해결코드 -2

test() {
      axios.get('/api/error/bad', {params: {param: 'go'}})
        .then(res => {
          console.log(res);
          this.result = res.data;
          
          // FIX 
        }).catch((error) => {
            console.log('error!',error);

            // return msg
            const errorRes = error.response.data;
            console.log('error data',errorRes);
            let code = '';
            switch (errorRes.msg){
              case 'day':
                code = '런타임에러'; break;
              default:
                code = '잘못된 요청';
                break;
            }
            // 문제의 코드
            this.error.msg = code;
      });
    }

- Arrow function(화살표 함수) 을 사용하는 방법이다. 

해당 함수는 자신의 this 객체를 가지고 있지 않기 때문에 해결 가능한 방법이다.

 


JS Object, this 의 개념에 대해서 알고 있었다면, 금방 해결할 수 있는 이슈였다. 

기본 개념을 잘못 알고있는것은 아닌지,

에러 핸들링을 어떻게 하면 효율적일지 다시 생각해 볼 수 있는 장애대응이었다

반응형

댓글