[WEB] Ajax

Ajax : Asynchronous JavaScript and XML (XMLHTTPRequast 통신)

  비동기로 서버로부터 데이터를 가져오는 기술이다. 웹에 데이터를 갱신할 때, 브라우저 새로고침 없이 서버로부터 데이터를 받는 것이 더 좋은 UX를 제공할 수 있겠다 좋겠다는 생각에서 출발했다. '비동기적으로', 즉 화면의 다른 부분에는 영향을 주지 않고 선택한 탭의 내용만 바꿔주는 식의 기술이다. Ajax 통신의 기본은 XMLHTTPRequest 객체이다.

XMLHTTPRequest Method
  • open() : 서버로 보낼 ajax 요청의 형식을 설정한다.
open(전달방식, url주소(파일위치), 동기여부);
전달방식 : GET 또는 POST방식 중 하나를 선택할 수 있다. 대문자로 쓰지 않으면 간혹 브라우저에서 인식하지 못하는 경우도 있으니 되도록 대문자로 입력하자. 
URL 주소는 요청을 처리할 서버의 파일 주소이다. 
동기 여부는 요청을 동기식으로 전달할지 비동기식으로 전달할지를 설정하는 것이다. default 값은 true로 비동기식 전달을 기본으로 한다. 
  • send() : 작성된 Ajax 요청을 서버로 전달한다.
요청방식에 따라 두가지 방식으로 사용된다.
send(); : GET 방식
send(문자열); : POST 방식

  • GET / POST 
GET 방식은 주소에 data를 추가하여 전달하는 방식이다. GET 방식의 HTTP 요청은 브라우저에 의해 캐시되어 저장된다. 또한 GET 방식은 보통 쿼리 문자열에 포함되어 전송되므로 길에 제한이 있고 보안상 취약하다. 속도가 빠르고 적은 양의 데이터를 보내기에 적합하므로 대부분의 통신은 GET 방식을 사용한다. 
예제

// GET 방식으로 요청을 보내면서 데이터를 동시에 전달함.
httpRequest.open("GET""/examples/media/request_ajax.php?city=Seoul&zipcode=06141"true);
httpRequest.send();


POST 방식은 data를 별도로 첨부하여 전달하는 방식이다. POST 방식의 HTTP 요청은 브라우저에 의해 캐시되지 않으므로 브라우저 히스토리에도 남지 않는다. 또한 POST 방식의 HTTP 요청에 의한 데이터는 쿼리 문자열과는 별도로 변송되어 데이터 길이에 대한 제한도 없고 GET 방식보다 보안성이 높다. 
Ajax 통신에서는 보통 POST를 사용한다. 

// POST 방식의 요청은 데이터를 Http 헤더에 포함시켜 전송함.
httpRequest.open("POST""/examples/media/request_ajax.php"true);
httpRequest.setRequestHeader("Content-Type""application/x-www-form-urlencoded");
httpRequest.send("city=Seoul&zipcode=06141");


open() send() 가 제대로 동작했다면 그 다음 사용할 수 있는 코드가 서버에 해당 문서가 존재하는지 확인하는 코드이다. 

if (httpRequest.readyState == XMLHttpRequest.DONE && httpRequest.status == 200 ) {
    ...
}
readyState 프로퍼티 값이 XMLHttpRequest.DONE 이면 서버에 요청한 데이터 처리가 완료되어 응답할 준비가 완료되었다는 의미이다. 또한 status 프로퍼티 값이 200이면 요청한 문서가 서버 상에 존재한다는 의미이다. 
  • json
  표준적 데이터 포맷을 결정하기 위해 주로 JSON(JavaScript Object Notation) 포맷을 사용한다. 클라이언트와 서버가 데이터를 주고받을 때 사용하는 포맷이다. 
JSON은 javascript object와 기본적으로 같고, key : value 형식으로 구성되어있다. 간단한 예제를 살펴보자

'temp.js'
1
2
3
4
5
6
var oReq = new XMLHttpRequest();
oReq.addEventListener("load"function(){
    console.log(this.responseText);
});
oReq.open("GET""./json.txt");
oReq.send();
cs

XMLHttpRequest 객체를 생성해서 open 메서드로 요청을 준비하고 json.txt 파일을 받아온다. 같은 디렉토리에 위치하는 json.txt 파일은 아래와 같이 만들어줬다.

1
2
3
4
{
    "name":"crong";
    "favorites" : ["apple","orange"];
}

cs

그리고 나서 send 메서드로 서버로 보낸다. 요청처리가 완료되면 (서버로 응답이 오면) load 이벤트가 발생하고 이벤트 리스터의 콜백함수가 실행된다. 콜백함수가 실행될 때는 이미 ajax 함수는 반환되고 콜스택에서 사라진 상태이다.
이렇듯 서버로부터 받아온 JSON 데이터는 문자열 형태임으로 브라우저에서 바로 실행할 수 없다. 따라서 문자열을 자바스크립트 객체로 변환한 후에야 데이터에 접근 할 수 있고 이를 하려면 문자열 파싱을 일일이 해야하는 불편함이있다. 이를 해소하기 위해 사용되는 방법이 브라우저에서 제공하는 JSON 활용해서 자바스크립트 객체로 변환하는 방법이다.

html 페이지를 하나 만들고 'temp.js'를 불러온다.
<script src="temp.js"></script>
html 파일을 서버에서 실행 하고 크롬 개발자 도구창을 열면 콘솔창에 json 파일의 내용이 출력된다. 간혹 보이지 않는경우가 있는데 콘솔 출력창 필터를 조절하면 나올 수도 있다.

 CORS 정책상 localhost에서 파일을 불러오는 file://을 통한 접근을 지원하지 않는다. 이 경우 서버를 만들어서 실행하거나 vs code 상에서 live server extension을 설치하여 html 파일에서 오른쪽 아래에 live server를 눌러주면 실행이 가능하다.

Ajax 코드를 하나 더 살펴보자


1
2
3
4
5
6
7
8
9
function ajax(){
    var oReq = new XMLHttpRequest();
    oReq.addEventListener("load",function(){
        console.log(this.responseText);
    });

    oReq.open("GET","http://www.example.org/example.txt");
    oReq.send();
}

4라인의 익명함수는 8,9 라인보다 더 늦게 실행된다. 이 익명함수는 비동기로 실행되며, 코드를 읽는 당시에 load 할때 이 함수를 실행해야 된다는 것만 알고 event queue 에 보관되다가, 서버로부터 데이터를 브라우저가 받으면 그때 call stack 에서 불러와져서 실행된다. 이것이 비동기적 통신이다. call back 함수는 무조건 비동기적 통신을 하며 call stack에 함수 형식에 따라 쌓인다는 것을 꼭 기억해야 한다.

동기적 / 비동기적 통신을 비교해보자.



참고 : http://www.phpmind.com/blog/2017/05/synchronous-and-asynchronous/

콜스택이란 무엇인가?

함수를 호출하면 call stack에 차례대로 쌓이게 되고 return 될 떄 까지 차례대로 stack에서 pop이 된다. 이 떄 stack의 크기를 넘어갈 정도로 함수호출이 쌓이면 stack overflow 혹은 blocking이 발생하게 된다. blocking이란 쉽게 말하면 slow code이다.
만약 call stack에 수행시간이 오래걸리는 작업이 들어있다면? 예를 들어 network에 연결하는 동작을 지시했다고 하자. 자바스크립트는 single thread 언어이고 이는 즉 한번에 하나의 동작밖에 수행하지 못한다는 뜻이다. 따라서 네트워크 요청이 끝날 때 까지 렌더링이나 동작시간이 짧은 작업들도 지연된다.
이를 해결하기 위한 가장 간단한 방법이 asynchronous call back 이다. 비동기  call back 함수가 호출되면 콜스택에 함수가 쌓이고 비동기 함수임을 web api(브라우저)가 인식하면 이를 callback queue에 push 하고 콜스택이 비워지고 나서 큐에 있는 동작들을 실행한다.
동기식 웹의경우 화면 렌더링도 스택이 비워져있는 상태에서만 가능하기 때문에 작업이 처리되는동안 사용자는 아무것도 할 수 없다.

cross domain 문제

XHR 통신은 다른 도메인간에는 보안을 이유로 요청이 되지 않는다. 즉 A도메인에서 B도메인으로 XHR통신, Ajax 통신을 할 수 없다. 이를 회피하기 위해 jsonp라는 방식이 널리 사용되고 있고 최근에는 CORS라는 표준적인 방법이 등장했다.
jasonp는 아직도 많은 곳에서 사용하는 비표준 방식이다. 사실상 표준으로 사용하는 것으로 cors로 가기전 많은 곳에서 사용중이므로 사용법을 알아두면 좋을 것이다. 

jasonp의 동작방신은 크롬개발자도구의 networks 패널을 열고 살펴보면 좋다.
네트워크 탭에서 화면에 새로고침없이 변화를 주고 있는데 xhr 탭에 아무 것도 없고 js 탭에 변화가 있다면 그는 jasonp 방식으로 구현된 사이트라고 볼 수 있다.

JSONP 방식은 위의 Ajax 통신에서 쓰였던 XMLHttpRequest 객체가 아닌 <script>태그를 사용하는 방식이다. HTML의 script 요소로부터 요청되는 호출에는 보안상 정책이 적용되지 않는다는 점을 이용한 우회방법이다.
https://www.w3schools.com/js/js_json_jsonp.asp
위 링크를 참고하여 JSONP 방식의 예제들을 직접 실행 해 볼 수 있다.

참고 ) 
https://developer.mozilla.org/en/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest

No comments:

Powered by Blogger.