AJAX로 구현하는 비동기 데이터 교환과 부분 화면 갱신

AJAX의 비동기 통신 구조와 Fetch·XMLHttpRequest 구현, 부분 갱신의 보안·상태 관리·운영 고려사항을 정리한다.

2026-08-14 · 최초 발행 2025-10-14

페이지를 다시 불러오지 않는 데이터 교환

AJAX(Asynchronous JavaScript and XML)는 JavaScript가 XMLHttpRequest 또는 Fetch API를 통해 서버와 비동기 통신하고, 응답을 받은 뒤 DOM을 조작해 화면 일부를 갱신하는 설계 패턴이다. 하나의 독립 기술이라기보다 여러 웹 기술을 결합하는 방식에 가깝다.

초기에는 XML이 중심이었지만 현재 데이터 교환에는 JSON이 주로 사용된다. 필요에 따라 XML과 XSLT를 활용할 수 있으며, XHTML·DOM·CSS는 표현 계층을 분리하는 역할을 맡는다. 대부분의 현대 브라우저가 관련 기능을 기본 지원하지만, 레거시 환경은 세부 동작과 지원 범위를 별도로 점검해야 한다.

비동기 요청을 구성하는 계층

AJAX는 데이터 계층(XML/JSON), 변환 계층(XSLT/템플릿), 표현 계층(DOM/CSS), 제어 계층(JavaScript)을 조합한다. 계층을 나누면 모듈화와 재사용성을 높일 수 있다.

표준 브라우저 API를 기반으로 하므로 플러그인에 의존하지 않고 여러 브라우저를 지원할 수 있다. 다만 통신은 CORS 정책과 Same-Origin 제약 안에서 구성해야 한다.

사용자 이벤트에 따른 요청을 UI 스레드와 분리하면 전체 페이지 리로드 없이 필요한 영역만 바꿀 수 있다. 그만큼 화면 깜빡임을 줄이고 상호작용을 강화할 수 있지만, 클라이언트와 서버에 나뉜 상태를 일관되게 관리해야 한다.

요청부터 부분 갱신까지의 흐름

요청은 클릭·스크롤·입력 같은 사용자 이벤트, 타이머, 관찰자(observer)에서 시작된다. 브라우저는 XMLHttpRequest나 Fetch 요청을 만들고 인증 정보와 토큰을 붙여 전송한다. 서버는 비즈니스 로직과 DB 트랜잭션을 수행한 뒤 JSON 또는 XML을 돌려주며, 클라이언트는 상태 코드에 따라 응답을 해석해 DOM 일부를 갱신한다.

ServerNetworkBrowser JSUserServerNetworkBrowser JSUseralt[성공(2xx)][클라이언트 오류(4xx)][서버오류/과부하(5xx/429)]UI 이벤트 발생입력 검증, CSRF 토큰/헤더 준비XHR/Fetch 요청 전송 (GET/POST, JSON/XML)요청 전달인증/권한, 비즈니스 로직, DB 트랜잭션응답(200/4xx/5xx, JSON/XML)응답 수신데이터 파싱(JSON.parse)DOM 업데이트, 상태 캐시재인증/입력오류 표시, 포커스 이동지수적 백오프 재시도, 장애 알림부분 화면 갱신

타임아웃과 네트워크 오류에는 지수적 백오프, 최대 재시도 횟수 제한, 사용자 피드백이 필요하다. GET과 PUT은 멱등이고 POST는 비멱등이므로, 재시도 대상은 중복 방지 키까지 고려해 정한다. 서버 트랜잭션 경계를 분명히 하고, 부분 실패에는 보상 트랜잭션 또는 롤백 처리를 둔다.

화면 상호작용에 적용하는 방식

자동완성이나 라이브 검색은 입력 이벤트마다 서버 검색 API를 호출해 결과 목록을 동적으로 바꾼다. 무한 스크롤과 페이지네이션은 IntersectionObserver가 뷰포트 진입을 감지하면 다음 페이지를 비동기로 불러오는 형태다.

지역·카테고리처럼 서로 종속된 셀렉트 박스는 상위 선택값이 바뀔 때 하위 옵션을 갱신한다. 폼 자동저장과 드래프트 기능은 입력 변경을 감지한 뒤 디바운스 전송하고, 충돌이 발생하면 버전 필드로 병합한다. 대시보드는 위젯별 폴링이나 SSE·WebSocket을 병행해 최신 데이터를 반영할 수 있다.

부분 데이터 전송을 기준으로 평균 응답 체감 시간은 30~70% 단축되고, 전송 바이트는 40% 이상 줄어들 수 있다. 서버 사이드 템플릿 렌더 비율을 낮추고 API를 재사용하면 서비스 간 결합도도 완화된다. 화면 깜빡임을 줄이는 효과는 상호작용성과 전환율·체류시간 개선으로 이어진다.

Fetch와 XMLHttpRequest 구현

현대 브라우저, HTTPS, JSON API를 전제로 한다면 Fetch API를 기본 패턴으로 사용할 수 있다.

async function loadUser(userId) {
  const resp = await fetch(`/api/users/${encodeURIComponent(userId)}`, {
    method: "GET",
    headers: {
      Accept: "application/json",
      "X-CSRF-Token": window.csrfToken,
    },
    credentials: "same-origin",
  });
  if (!resp.ok) throw new Error(`HTTP ${resp.status}`);
  const data = await resp.json();
  document.querySelector("#user-name").textContent = data.name;
}

레거시 호환이 필요할 때는 XMLHttpRequest 패턴을 폴백으로 둘 수 있다.

function loadList(page) {
  const xhr = new XMLHttpRequest();
  xhr.open("GET", `/api/items?page=${encodeURIComponent(page)}`, true);
  xhr.setRequestHeader("Accept", "application/json");
  xhr.onload = function () {
    if (xhr.status === 200) {
      const items = JSON.parse(xhr.responseText);
      // DOM 업데이트 로직
    } else {
      console.error("HTTP", xhr.status);
    }
  };
  xhr.onerror = function () {
    console.error("Network error");
  };
  xhr.send();
}

브라우저에 남는 공격 표면

응답값이나 입력값을 DOM에 직접 넣으면 Reflected·Stored·DOM 기반 XSS가 발생할 수 있다. 소스 맵이나 디버그 빌드가 유출되면 내부 로직과 API 키가 노출될 위험도 있다. LocalStorage를 비롯한 토큰·세션 저장소의 오남용, 민감 데이터 캐시, CSRF, CORS 오구성, JSONP 남용, 취약한 라이브러리 버전도 점검 대상이다.

컨텍스트에 맞춰 HTML·URL·JS·CSS를 이스케이프하고, innerHTML 대신 textContent를 사용한다. CSRF 토큰과 SameSite=Lax/Strict 쿠키, Authorization 헤더를 관리하며 TLS(HTTPS)를 적용한다. 민감 데이터는 서버 측에서 암/복호와 토큰화를 수행한다.

CSP와 Subresource Integrity(SRI)를 적용하고 외부 스크립트를 제한한다. 서버와 클라이언트 양쪽에서 입력 검증과 출력 인코딩을 수행하며, DOMPurify 등을 사용할 수 있다. API 키는 서버에 보관하고 프런트에 노출하지 않으며 소스맵은 비공개로 배포한다. CORS는 Origin 화이트리스트, 자격증명 전달 제한, 엄격한 프리플라이트 응답으로 최소화한다.

상태·캐시·관측성을 함께 설계하기

ETag·Last-Modified와 Cache-Control(max-age, stale-while-revalidate)을 적용하고, 멱등 요청을 우선 캐싱한다. 낙관적 업데이트를 사용할 때는 version 또는 etag 기반의 충돌 해결 정책과 실패 시 롤백 UX가 필요하다.

동적 콘텐츠에는 ARIA 라이브 리전을 사용한다. SEO가 필요한 경우에는 SSR 또는 프리렌더를 병행한다. 오류는 문제 상세 RFC 7807 같은 표준화된 포맷으로 만들고, 프런트 로깅과 트레이싱을 연결한다.

단순 비동기 요청에는 Fetch를 권장하며, 스트리밍이나 대용량 전송에는 Stream API, 실시간 갱신에는 SSE 또는 WebSocket 병행을 고려한다.

지표 전체 리로드 AJAX 부분 갱신
성능 매 요청 전체 HTML 전송, 렌더 비용 큼 필요한 데이터만 전송, 렌더 범위 축소
확장성 서버 템플릿 결합도 높음 API 중심, 클라이언트 렌더 분담
일관성 서버 렌더 단일 트랜잭션 클라이언트/서버 분산, 동기화 정책 필요
안정성 단순 흐름, 실패 시 전체 재시도 부분 실패 처리/재시도 로직 필요
운영 편의 SEO/접근성 용이 상태/캐시/보안 구성 필요

API를 설계할 때는 리소스 경로·메서드·스키마를 정하고 JSON과 오류 포맷을 표준화한다. 전송 계층에서는 Fetch와 XHR 폴백, CORS·인증·토큰을 결정한다. 이어 DOM 업데이트 경계와 로딩·오류 상태를 컴포넌트화하고, 타임아웃·백오프·멱등성·사용자 피드백 정책을 마련한다.

CSRF·CSP·SameSite·HTTPS와 특수문자 처리, 비밀 관리를 보안 설정에 포함한다. 마지막으로 로그·메트릭·추적을 연결하고 캐싱·페이징·페이로드 압축(Gzip/Brotli)을 적용한다.

AJAX비동기 통신웹 개발보안Fetch API