오류 발생에 대한 전체적인 흐름 및 회고.
아래 JS 문법에 대한 방법은 2-2번 항목에 존재.
TypeError: undefined is not an object (evaluating 'this.error.use = msg')
**환경
- Front: Vue2 + option API
- Back: Spring Boot(Rest)
1. 장애 상황 및 이슈
- 글 작성일 기준일 오후중 운영환경에서 발생한 장애 이슈.
클라이언트에게 보여지면 안되는 오류얼럿 메시지가 노출되고, 사용자의 요청 결과를 출력하지 않는 이슈발생
- 흐름
프론트단에서의 클릭 이벤트 발생 -> 서버단에서의 각종 유효성 조회 및 검증 -> 검증통과시 http status 200 return - end
front 의 콜백함수에는 서버단에서 발생할 수 있는 Exception에 대한 Error Handling 이 되어있는 상태였다(catch).
그렇다면 여기서 의심할 수 있는 상황은 이렇다.
- 서버단에서 발생하는 추가적인 Exception 발생.
- 추가된 Exception 은 없지만, 에러 핸들링에 대한 처리 미흡.
- 오류 얼럿 메시지에 기반한, 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 의 개념에 대해서 알고 있었다면, 금방 해결할 수 있는 이슈였다.
기본 개념을 잘못 알고있는것은 아닌지,
에러 핸들링을 어떻게 하면 효율적일지 다시 생각해 볼 수 있는 장애대응이었다
댓글