요구사항 발생 원인
더블 클릭으로 인한 POST 중복 호출로 동일 데이터가 여러개 생성
해결 방안 모색
버튼에서 더블 클릭을 방지하는 방안
방안 | 비고 |
---|---|
기존 화면에 있는 기본 버튼을 custom 한 directive로 대체 | 테스트 시간 소요, 누락 가능성 |
버튼 외에 키보드 이벤트 등 으로도 api 가 호출 가능 | 모든 경우의 수 고려 필요, 누락 가능성 |
위 경우의 수 누락을 방지하기 위한 api 중복 호출을 막기 | 결국 중복 기능이 되어버림 |
api 호출 관련이 아닌 중복 동작 처리에 사용하는 것이 적합해 보임
api 호출 직전에 중복 호출 막는 방안
방안 | 비고 |
---|---|
interceptor 를 이용하여 api 호출 직전, 이전 api를 체크 | interceptor request |
다른 directive 에서 동일한 api를 거의 동시에 호출하는 경우 문제 발생 | POST, PUT, DELETE 만 대상 |
코드로 인한 연속 호출인 경우에 문제가 발생할 수 있음 | 필요시 예외 flag |
화면에서 사람에 의한 중복 호출만 있다는 가정 |
인터페이스를 통한 막기 보다는, 최종 단계 직전에서 막는 것이 더 심플할 것으로 판단
interceptor 사용하는 것이 더 효과적이라고 생각 됌
interceptor
angularJS $http 에서 제공함.
현재 개발중인 프로젝트는 1.6.10
1.6.10 버전은 $resource interceptor 는 response, responseError 만 처리할 수 있음.
(1.6.10 버전 $http는 request, requestError 제공)
프로젝트 angularJS 버전을 올려야 함 > 1.7.8 로 올림 > 모든 기능 테스트 필요
참조
migrating-from-1.6-to-1.7
$resource:1.6.10
$resource:latest
$http#interceptors:1.6.10
$http#interceptors:latest
api 중복 호출 처리
/**
* 더블 클릭 방지 코드
* 목적: 더블 클릭 방지
* 동일 url 이 response 되지 않은 상황에서 재호출 막기
* 동일 url, 동일 method 을 호출할 경우 중복으로 처리
* response, responseError 로 반드시 종료 처리가 되기 때문에, 요청 시간 정보는 불필요
* url을 key 로 하면 탐색시간이 O(1) 이므로 검색 속도가 빠르므로 simple 하게
* {
* 'GET': {
* url1: true,
* url2: true
* },
* 'POST': {
* url1: true,
* url2: true
* }
* }
* 위 형태로 요청 중인 정보를 가지고, response(Error) 시 delete 처리
* @author heather
*/
var requestingUrlData = {};
function addRequestData(config) {
if (config.method === 'GET') { return; }
requestingUrlData[config.method] = requestingUrlData[config.method] || {};
requestingUrlData[config.method][config.url] = true;
}
function removeRequestData(config) {
if (config.method === 'GET') { return; }
var methodData = requestingUrlData[config.method] || {};
delete methodData[config.url];
}
function isDoingSameRequest(config) {
var methodData = requestingUrlData[config.method] || {};
return methodData[config.url];
}
/** - 더블 클릭 방지 코드 끝 */
return {
request: function(config) {
if (!config.passSameCall && isDoingSameRequest(config)) {
// '중복 허용이 아님' && '현재 동일 api 호출 후 리턴이 오지 않음'
// passSameCall 는 resource 호출 시 설정 함.
return $q.reject({
error: 'same request called',
pass: true,
config: config
});
}
// 호출 시작
addRequestData(config);
return config;
},
requestError: function(rejection) {
// 호출 완료
removeRequestData(rejection.config);
return $q.reject(rejection);
},
response: function (response) {
// 호출 완료
removeRequestData(response.config);
return response.data;
},
responseError: function (error) {
// 호출 완료
removeRequestData(error.config);
if (error.pass) {
return $q.reject(error);
}
return error.data;
}
};
// $resouce 호출
doApi : function() {
var url = 'url';
var action = actionFactory.defaultAction;
var params = {};
// 중복호출 허용 설정
action.create.passSameCall = true;
return $resource(url, params, action);
},