탱구탱구 개발자 일기

개요

앞의 포스팅에서 HTTP 통신에 대해 알아보면서 JavaScript에서는 AjaxXMLHttpRequest 객체를 이용하여 웹서버와 비동기적으로 통신하고 DOM을 제어하여 동적인 웹 페이지를 만든다고 설명하였다. 이 때 Ajax는 Asynchronous JavaScript and XML의 약자로 직역하면 비동기 자바스크립트와 XML이다.

XML는 마크업 언어인데 초창기 Ajax에서 사용하는 데이터 형식이었다. 내가 처음에 코딩을 배울 때만 해도 공공 데이터 포털이나 네이버, 카카오 개발자 센터같이 API를 제공하는 곳에서 문서를 살펴보면 XML과 JSON 형태를 둘 다 제공하였다. 그러나 거의 요즘은 JSON 형태로만 제공한다.

 

예제

window.onload = function () {
    // 1. XMLHttpRequest 객체 생성
    let req = new XMLHttpRequest();
    // 2. 서버와 통신할 때 사용할 처리 방법을 등록
    req.onreadystatechange = function () {
        if (req.readyState == 4) {
            if (req.status == 200) {
                document.getElementById("view").innerHTML = req.responseText;
            }
        }
    };
    // 3. 요청을 전송하고 통신을 시작함
    req.open("GET", "file:///C:/Users/junyoung/Desktop/data.txt");
    req.send(null);
}

 

기본적인 통신 방법은 위와 같다. 그러나 위 소스를 불러오는 html 페이지에서는 브라우저 보안상 로컬 경로의 파일을 접근할 수 없다. 따라서 원칙적으로는 웹서버에 파일을 올려놓고 접근해야한다.

 

또한 기본적으로 XMLHttpRequest 객체는 크로스 오리진 통신을 금지한다. 예를 들어 A사이트에서 Ajax를 통해 B사이트의 데이터를 불러오려고 할 때 다음과 같은 에러가 발생한다.

Access to XMLHttpRequest at 'https://naver.com/' from origin 'http://localhost:63342' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

origin인 localhost에서 naver로의 XMLHttpRequest 요청이 CORS policy에 의해 차단되었다는 뜻이다. 원칙적으로 XMLHttpRequest Level 1에서는 도메인이 다른 데이터를 가져올 수 없었다. 그러나 Level 2부터는 제한적인 크로스 오리진 통신을 허용한다.

 

※ 대표적인 제한적인 크로스 오리진 통신 방법

  • JSONP(JSON width Padding)
  • CORS(Cross Origin Resource Sharing)
  • postMessage

※ JSONP

'script' 요소의 src 속성이 가리키는 자바스크립트 파일은 다른 도메인에 위치해도 읽어 들일 수 있다'라는 성질을 활용한 기법이다. JSONP의 P를 padding인데 JSON 데이터에 함수 이름을 추가하겠다는 뜻이다. 

 

  1. 외부 서버에 json_test.js 라는 자바스크립트 파일이 업로드 되어 있고 해당 파일에는 getData라는 이름을 가진 함수의 인수로 JSON 형태의 JSONP 데이터가 들어있다.
  2. 클라이언트에서 이벤트를 통해 script DOM 요소를 생성하고 src 속성 값으로 외부 서버의 json_test.js 주소를 대입한다.
  3. 2번을 통해 외부 서버가 해당 파일을 클라이언트로 보낸다.
  4. 클라이언트에서는 json_test.js 파일에 정의한 getData 함수를 정의하여 해당 JSON 데이터를 읽어올 수 있다.

중요한 것은 외부 서버의 json_test.js가 클라이언트에 정의된 getData 함수를 실행하는 것이다.

 

※ CORS

 

앞서 말했듯이 XMLHttpRequest Level 2에선 제한적으로 크로스 오리진 통신을 허용한다고 했다. 이를 CORS라고 한다. CORS는 데이터를 가져오려는 도메인이 악의적이라면 접근을 차단해야하지만 신뢰있는 도메인일 경우 접근을 허용하자는 것이다.

 

보통 웹서버에서는 라이브러리로 해결하기 때문에 Java 진영의 tomcat에서는 cors.jar라는 이름으로 많이 알려져 있다.

 

보통 파일을 통해 해결하거나 응답 Header에 code를 넘긴다. 공통적으로 들어가는 형태는 다음과 같다.

Access-Control-Allow-Origin: 허용할 url

이 때 모든 사이트를 대상으로 접근( or 읽기, 쓰기)을 허용하려면 특수문자 *를 적어주면 된다.

 

※ postMessage

 

Window.open 메서드를 통해 부모 창에서 자식 창을 열면 Window 객체를 통해 조작이 가능하다. 이는 iframe으로 불러온 웹 페이지에도 적용되는데, 만약 두 페이지 간에 도메인이 다를 경우 크로스 도메인 정책에 따라서 다른 페이지의 데이터를 가져오는 것은 여전히 불가능했었다. 즉, window 객체를 통한 객체의 프로퍼티 or 메서드를 사용할 수 없다는 것이다.

 

그러나 HTML5이 등장하고 Window 객체의 postMessage 메서드를 활용하면 상호 간의 프로퍼티나 메서드를 실행할 순 없지만 다른 도메인끼리 메시지를 비동기적으로 주고받을 수 있다. 

결론

실무에서는 위 예제처럼 XMLHttpRequest 객체를 직접 생성하여 사용하는 경우는 드물다. 왜냐하면 jQuery나 Axios등의 라이브러리에서 간편하게 Ajax를 사용할 수 있기 때문이다.

이 글을 공유합시다

facebook twitter kakaoTalk kakaostory naver band
loading