[TIL] 03.02 iamport를 통한 naverpay 연동 및 axios interceptors

2021. 3. 2. 23:16TIL

한동안 iamport 를 통해서 naverpay 연동을 위한 작업을 진행하였다. 

결제 로직상 에서 naverpay를 paymethod로 받을 수 있는 작업은 완료가 되어 있었기에 관련 서류를 준비해 요청을 보내고 iamport에 naverpay 검수 요청을 보냈다. 

naverpay를 적용 하기 위해서는 통과해야 하는 요건들이 있는데 그 중 아래 3가지 문제에 대해서 통과하지 못했다. 

 

1. naverpay 객체를 보내야 한다. 

2. 에러 메시지는 가공 되어서는 안된다.
    ex) 결재실패: 결재 오류가 발생했습니다. (X)

          결재 오류가 발생했습니다.(o)

3. 위변조된 결제 건에 대하여 자동으로 취소 요청을 하고 이용자에게 해당 결제가 위변조 되었다는 사항을 전달해야함 

 

1,2 번 문제는 쉽게 해결을 하였는데 3번 문제에 시간이 꽤 걸렸다. 

지금 프로젝트에서 결제 페이지에서 결제를 하고 결제 완료 페이지에서 complete 라는 api 를 사용해서 결제 정보를 가져오도록 되어 있다. 

해당 결제 정보는 webhook에서 받아 db에 저장이 된 데이터를 가져오도록 되어있다. 

그런데 위조의 경우 처음에는 우선 성공으로 결제 정보를 보내오고 해당 결제 정보와 우리 서버에 저장되어진 결제 정보를 비교하여 결제 정보에 차이가 있다면 취소 요청을 보내고 위조된 결제 정보로 저장을 하게 된다. 

 

여기서 문제는 위조일 경우 결제 정보 데이터를 바로 저장하지 않고 결제 취소 후 해당 결제 정보를 저장하는데 complete api와 iamport webhook이 병렬적으로 실행이 되어서 webhook보다 complete api 의 속도가 더 빠른 경우 결제 정보가 저장되기 전이라서 404 에러가 나는 것이다. 

 

그래서 api 호출을 실패 했을 경우 다시 한번더 api 를 호출 할 수 있는 방법을 찾아보다가 아시는 분의 도움으로 axios의 interceptor 라는 기능을 알게 되었다. 

interceptor는 axios 요청을 전역적으로 보고 있다가 request 전 response 후 then, catch 로 넘어가기 전에 값을 가로채어 추가적인 작업을 할수 있도록 해준다.

 

처음엔 axios-retry 라이브러리를 사용 하였는데 제대로 실행이 되지 않아서 다시 문서를 확인 해보니 0.19 버전에서는 bug가 있어서 0.19.1 버전을 사용해야 한다는 것이였다. 그래서 해당 이슈를 들어가서 다른 해결책을 찾아 보았고 해당 방법을 사용하여 라이브러리를 사용하지 않고 구현을 해주었다. 

axios-retry: www.npmjs.com/package/axios-retry

axios 0.19.0 버전 이슈: github.com/axios/axios/issues/2203

// next의 getInitialProps 함수  
Confirmation.getInitialProps = async (ctx): Promise<Partial<Props>> => {
    const uid = 결제 아이디;
	
    let retries = 0;

    const paymentInterCeptors = axios.interceptors.response.use(
    	// 응답이 성공 했을 경우는 바로 return 해준다. 
        function (response) {
            return response;
        },
        // 응답이 실패했을 경우
        function (error) {
            retries = retries + 1;
            
			// retries 가 3보다 크거나 404에러가 아닐 경우 Promise reject을 해준다.
            if (retries >= 3 || error.response.status !== 404) {
                retries = 0;
                return Promise.reject(error);
            }
            
            // retries 가 3보다 작거나 404에러일 경우만 다시 api 호출을 해준다.
            return new Promise((resolve) => setTimeout(() => resolve(axios(error.config)), 3000));
        },
    );

    const response = await api({
        method: 'post',
        url: `/complete`,
        data: {
            id: 결제 아이디 
        },
    });

    try {
        return {
            result: {
                data: response.data,
                success: true,
                status: 200,
            },
        };
    } catch (e) {
        return {
            result: {
                data: null,
                success: false,
                status: 400,
            },
        };
    } finally {
    	// interceptor가 eject 되지 않아서 여러번 호출이 되는 경우가 있어서 interceptor를 넘어 오는 경우 eject 해주도록 처리
        axios.interceptors.response.eject(paymentInterCeptors);
    }
};

1.  먼저 complete api 호출을 한다. 

2. 호출의 응답이 왔을 때 interceptor내의 로직이 실행이 된다. 

3. interceptor 에서 총 3번의 시도를 하고 그 중 성공으로 결과가 나오면 try 로 진행이 되고 실패로 결과가 나오면 catch 로 진행이 된다. 

 

axios-interceptor 참고 문서 

axios 공식 문서: github.com/axios/axios#interceptors

axios 가이드: xn--xy1bk56a.run/axios/guide/interceptors.html

 

'TIL' 카테고리의 다른 글

[TIL] 01.21 배너 작업, 실시간 시계  (0) 2021.01.23
[TIL] 01.20  (0) 2021.01.20
[TIL] 01.19  (0) 2021.01.19
[TIL] 01.18 페이스북 로그인 문제  (2) 2021.01.18
[TIL] 01.14 결제 폼 디자인 수정 작업  (0) 2021.01.14