웹 애플리케이션을 개발할 때, 모든 API 요청(AJAX 또는 Fetch API)에서 반복적으로 공통 헤더를 추가하고 에러를 글로벌로 핸들링할 필요가 있습니다. 특히 401 Unauthorized 응답을 감지하여 자동으로 로그인 페이지로 이동하는 기능이 중요합니다.
이번 글에서는 AJAX(jQuery)와 Fetch API에서 공통 헤더를 설정하고, 글로벌 에러 핸들링을 구현하는 방법을 정리합니다.
1. jQuery AJAX에서 글로벌 설정
📌 공통 헤더 설정 및 에러 핸들링
$.ajaxSetup()을 사용하면 모든 AJAX 요청에 대해 공통적인 설정을 적용할 수 있습니다.
$.ajaxSetup({
beforeSend: function(xhr) {
let token = $("meta[name='_csrf']").attr("content");
let header = $("meta[name='_csrf_header']").attr("content");
if (token && header) {
xhr.setRequestHeader(header, token); // ✅ CSRF 토큰 자동 추가
}
},
error: function(xhr) {
if (xhr.status === 401) { // 🔹 401 응답을 받으면 로그인 페이지로 이동
alert("로그인이 필요합니다. 로그인 페이지로 이동합니다.");
window.location.href = "/login";
}
}
});
📌 AJAX 글로벌 에러 핸들러 설정
$(document).ajaxError()를 활용하면 모든 AJAX 요청에서 발생한 에러를 감지할 수 있습니다.
$(document).ajaxError(function(event, xhr, settings, thrownError) {
if (xhr.status === 401) { // 🔹 401 감지 후 로그인 페이지로 이동
alert("세션이 만료되었습니다. 로그인 페이지로 이동합니다.");
window.location.href = "/login";
}
});
✔ 모든 AJAX 요청에서 401 Unauthorized 응답을 감지하여 자동으로 로그인 페이지로 이동
✔ CSRF 토큰을 모든 요청에 자동 추가하여 보안 강화
2. Fetch API에서 글로벌 설정
Fetch API에는 $.ajaxSetup()과 같은 기능이 없기 때문에, 공통 헤더를 추가하고, 글로벌로 401 Unauthorized 응답을 감지하는 래퍼 함수를 만들면 해결할 수 있습니다.
📌 Fetch API 요청을 감싸는 fetchWithAuth() 함수
function fetchWithAuth(url, options = {}) {
// ✅ 기본 헤더 설정
const defaultHeaders = {
"Content-Type": "application/json",
"X-CSRF-TOKEN": document.querySelector("meta[name='_csrf']")?.content || ""
};
// ✅ 기존 옵션과 병합
options.headers = { ...defaultHeaders, ...options.headers };
return fetch(url, options)
.then(response => {
if (response.status === 401) { // 🔹 401 감지 후 로그인 페이지로 이동
alert("세션이 만료되었습니다. 로그인 페이지로 이동합니다.");
window.location.href = "/login";
return Promise.reject("로그인 필요");
}
return response.json();
})
.catch(error => console.error("Fetch 요청 중 오류 발생:", error));
}
// ✅ 사용 예제
fetchWithAuth("/protected-resource")
.then(data => console.log("응답 데이터:", data))
.catch(error => console.error("에러 발생:", error));
✔ CSRF 토큰을 자동으로 추가하여 보안 강화
✔ 401 Unauthorized 응답을 감지하여 로그인 페이지로 이동
📌 window.fetch를 오버라이드하여 Fetch API 글로벌 설정
기존 fetch()를 직접 오버라이드하면 모든 fetch() 요청에서 자동으로 공통 헤더를 추가하고 401을 감지할 수 있습니다.
// ✅ 원래 fetch 함수를 백업
const originalFetch = window.fetch;
// ✅ fetch를 오버라이드하여 401 응답 감지 & CSRF 토큰 자동 추가
window.fetch = function(url, options = {}) {
const defaultHeaders = {
"Content-Type": "application/json",
"X-CSRF-TOKEN": document.querySelector("meta[name='_csrf']")?.content || ""
};
options.headers = { ...defaultHeaders, ...options.headers };
return originalFetch(url, options)
.then(response => {
if (response.status === 401) { // 🔹 401 응답을 받으면 로그인 페이지로 이동
alert("세션이 만료되었습니다. 로그인 페이지로 이동합니다.");
window.location.href = "/login";
return Promise.reject("로그인 필요");
}
return response;
})
.catch(error => {
console.error("Fetch 요청 중 오류 발생:", error);
throw error;
});
};
✔ 모든 Fetch 요청에서 자동으로 공통 헤더를 추가
✔ 401 Unauthorized 응답을 감지하여 로그인 페이지로 이동
✔ 기존 fetch()를 수정하지 않고도 자동 적용
3. 백엔드(Spring Boot)에서 401 Unauthorized 응답 반환
위의 JavaScript 설정과 함께, Spring에서 로그인이 필요한 경우 401 Unauthorized를 반환해야 합니다.
@ExceptionHandler(ServletRequestBindingException.class)
public ResponseEntity<ResponseDto> handleServletRequestBindingException(ServletRequestBindingException ex) {
return ResponseEntity.status(HttpStatus.UNAUTHORIZED)
.body(ResponseDto.builder().code(0).msg("로그인이 필요합니다.").build());
}
✔ 401 Unauthorized 응답을 보내야 프론트에서 감지 가능
🔹 결론
✅ jQuery AJAX: $.ajaxSetup()과 $(document).ajaxError()를 사용하여 전역 에러 핸들링 및 공통 헤더 설정
✅ Fetch API: fetchWithAuth() 함수 또는 window.fetch를 오버라이드하여 전역적으로 401 Unauthorized 감지 및 공통 헤더 추가
✅ 백엔드(Spring Boot): 로그인이 필요한 경우 401 Unauthorized 응답 반환
이제 AJAX와 Fetch API에서 글로벌로 공통 헤더를 추가하고, 401 Unauthorized 응답을 자동으로 감지하여 로그인 페이지로 이동하는 기능을 구현할 수 있습니다! 🚀