# 자바스크립트 & 제이쿼리 (jpub) - 8장 Ajax와 JSON
# Ajax
- 언제?
- 검색어 자동완성
- 장바구니에 아이템 추가
- 비동기
- 동기 처리 모델: 원래 브라우저는
<script>
태그를 만나면 스크립트를 로드하고 처리하기 전까지 다른 작업은 중단 - ajax의 비동기 처리 모델(aka non-blocking 처리모델)
- 1 브라우저는 서버에 데이터 요청
- 이 요청은 서버가 필요로 하는 정보를 포함하기도 함
- 브라우저는 ajax요청을 담당하는 XMLHttpRequest라는 객체를 구현하고 있음.
- 일단 요청을 전송하고 나면, 브라우저는 서버의 응답을 기다리지 않는다.
- 2 서버는 응답으로 데이터를 전달
- 주로 HTML, XML, JSON형식
- 서버에서 일어나는 일들은 ajax라 부르는 처리과정에 포함X
- 3 서버가 요청에 대한 응답을 완료하면 브라우저에선 이벤트가 발생.
- 이 이벤트는 데이터를 처리하여 페이지의 일부를 변환하는 js함수를 호출
- 1 브라우저는 서버에 데이터 요청
- 동기 처리 모델: 원래 브라우저는
- ajax를 이용하면 페이지의 일부를 수정하고 싶을 때 어느 특정 요소의 컨텐츠를 업데이트 하면 된다.
- 그러려면 이벤트를 가로채 서버에 새로운 콘텐츠를 요청하는 비동기 요청 보냄 된다.
# Ajax 요청 및 응답처리
- 브라우저는 XMLHTtpRequest객체르 이용해 Ajax요청을 생성.
- 서버가 브라우저의 요청에 대해 응답을 전달하면 같은 XMLHTTPRequest객체가 그 결과를 처리함.
//요청
var xhr = new XMLHttpRequest(); //new로 생성.
xhr.open('GET', 'data/test.json', true); //open(http메서드, 요청을 처리할 페이지의 url, 요청이 비동기로 처리될 것인지를 지정하는 불리언)
xhr.send('search=arduino'); //준비된 요청을 전달. 괄호 내에 서버에 전달될 추가 정보 전달할 수도 있음.
//응답
xhr.onload = function() { //브라우저가 서버로부터 응답을 받으면 onload이벤트가 발생.
if(xhr.status == 200) { //xml객체의 status속성값을 검사하고 서버의 응답이 정상인지 확인
//서버의 실행 결과를 처리할 코드
}
}
# 데이터 타입
- Ajax응답은 주로 HTML, XML, JSON중 한 가지 형식으로 전달된다.
- HTML
- 웹페이지의 일부를 업데이트하고 싶은 경우 페이지에 데이터를 표현하기 위한 가장 간단한 방법.
- pros
- 코드 작성 및 요청 처리하고 응답 표시하기가 간편
- 서버로부터 전달된 데이터를 곧바로 페이지에 삽입가능. =>브라우저가 별도로 처리할 필요 없다.
- cons
- 서버가 반드시 페이지에서 사용할 수 있는 HTML을 리턴해야 함.
- 웹 브라우저가 아닌 애플리케이션엔 적합 ㄴㄴ => 데이터 이식성이 좋지 않음.
- 요청이 반드시 같은 도메인으로부터 이루어져야 한다.
- ajax응답이 html나 xml형식인 경우엔 페이지와 같은 도메인에서 전달된 것들만 허용.
- XML
- html랑 비슷하지만 태그의 이름이 다르다.
- 이는 xml이 저장되어있는 데이터를 묘사하기 때문.
- 문법 또한 HTML에 비해 훨씬 제한적.
- pros
- 유연한 데이터 타입 => 복잡한 구조의 데이터도 표현가능
- 이기종 및 응용프로그램 사이의 데이터교환에 적합
- HTML과 동일한 DOM메서드들을 통해 처리 가능.
- cons
- 태그 때문에 실제 데이터 외에도 추가로 많은 문자 사용 => 실제로 필요한 데이터보다 더 많은 양 대역폭 소비
- 요청이 반드시 같은 도메인에서 이루어져야함.
- 결과를 처리하기 위해 많은 양의 코드 작성해야 함.
- JSON
- JavaScript Object Notation
- 객체표현식과 유사한 용법을 사용해 데이터 표현.
- pros
- 다른 도메인에서도 요청을 보낼 수 있다.
- HTML, XML보다 강력
- 주로 js와 함께 사용.
- cons
- 문법에 예민. 따옴표 등을 실수하면 파일 전체 처리불가.
- js이기 때문에 악의적인콘텐츠를 가질 가능성이 있다.
- =>신뢰할 수 있는 곳에서 생성된 JSON만을 사용해야 한다.
# XML - 확장 가능한 마크업 언어
- html과 비슷하게 생겼지만 태그의 이름이 서로 다름.
- html과 동일한 돔조작 할수있는데, js보단 jquery로 하는게 더 낫다.
- xml파일의 태그는 그들이 가지고 있는 데이터를 설명할 수 있어야 함.
- xml은 모든 플랫폼에서 동작.
- 2000년대 초반에 많이 활용.
<?xml version="1.0" encoding="utf-8">
<events>
<event>
<location>샌프란시스코</location>
<date>5/1</date>
</event>
<event>
<location>한국</location>
<date>5/2</date>
</event>
</events>
# JSON - 자바스크립트 객체 표현식
- 객체 표현식과 거의 똑같이 생겼지만 순수 텍스트임.
- 실제 객체는 네트워크를 통해 전송할 수 없다. 그보다는 브라우저에 의해 객체로 변환될 수 있는 텍스트를 전달하는 것.
- 키는 반드시 작은따옴표 말고 큰따옴표로 둘러싸야한다.
- 값: string, number, Boolean, array, object, null
- js의 JSON객체는 JSON데이터를 js객체로 변환할 수 있다.
- 또한 js객체를 문자열로 변환하기도 함
JSON.stringify()
: js객체를 JSON형식의 문자열로 변환. 이를 이용해 js객체를 브라우저->다른 앱으로 전송가능.JSON.parse()
: JSON객체를 브라우저가 사용가능한 js객체로 변환.
{
"location": "샌프란시스코",
"date": 5,
"booking": true
}
{
"events": [ //이 배열에 객체 2개 저장.
{
"location": "샌프란시스코",
"date": 5,
"booking": true
},
{
"location": "서울",
"date": 6,
"booking": false
}
]
}
# Ajax로 HTML로드하기
- 서버가 요청에 응답할땐 반드시 상태 메시지를 전달하여 요청이 제대로 처리되었는지를 알려야 한다.
- 200: 서버가 응답 완료했으며 아무런 문제가 없다
- 304: 응답 내용이 이전 응답 내용과 동일하다
- 404: 페이지를 찾을 수 없다.
- 500: 서버 내부에서 오류가 발생했다
- 만일 이 코드를 로컬에서 실행하면 서버상태 속성을 받을 수 없을 때문에 이 속성을 검사하는 부분의 코드를 주석처리하고 조건식이 올바르게 실행될 수 있도록 true리턴해야 한다.
var xhr = new XMLHttpRequest();
xhr.onload = function() { //응답이 로드되면
if(xhr.status===200){ //서버 응답이 정상이면
document.getElementById('content').innerHTML = xhr.responseText;
}
};
xhr.open('GET', 'data/data.html', true); //요청 준비 - 방법/처리할페이지경로/비동기로할거
xhr.send(null); //요청 전송냐 - 여기서 서버 접속하고 응답 오면 위의 onload가 호출.
# Ajax로 XML 로드하기
- 조건식 내부의 응답을 처리하는게 좀 복잡. xml을 html로 변환해야 하기 때문.
- 책 380p 참고
# Ajax로 JSON로드하기
- json은 서버에서 문자열로 전송되어온다.
- 도착하면 이걸 js객체로 변환해야 한다. (역직렬화)
- JSON내장객체의 parse()메서드 사용하면 된다.
- 직렬화: stringify(). 브라우저->서버
var xhr = new XMLRequest();
xhr.onload = function() {
if(xhr.status===200){
responseObject = JSON.parse(xhr.responseText); //json가져와 js객체로 변경
var newContent = '';
for(var i=0; i<responseObject.events.length; i++) {
newContent += '<div class="event">';
newContent += '<img src"' + responseObject.events[i].location + '"';
...
}
document.getElementById('content').innerHTML = newContent;
}
};
xhr.open('GET', 'data/data.json', true); //요청 준비
xhr.send(null); //요청 전송
# 다른 서버로부터의 데이터 다루기
- ajax는 내가 보유한 서버로부터 전달된 데이터는 무리없이 처리가능하지만(보안상의 이유로)
- 다른 도메인으로부터의 ajax응답은 로드할 수 없다.(크로스 도메인 요청)
- 우회방법
- 웹 서버의 프록시 파일
- 서버에 원격서버로부터 데이터를 수집하는 파일을 생성(php, node, 루비 등 서버언어 이용해)
- 그럼 사이트 페이지에서 이 파일에 데이터 요청하면 됨.
- 이를 프록시(proxy)라고 함.
- JSONP
- JSON with Padding
- 데이터를 로드하는
<script>
요소를 다른 서버로부터 페이지에 추가. - 이 방법이 가능한 이유는 스크립트 태그의 원본 주소에 대한 제약이 존재하지 않기 때문
- 스크립트는 함수를 호출하며, 함수의 매개변수로는 JSON형식의 데이터가 전달.
- 이때 호출되는 함수는 페이지에 데이터를 요청하는 페이지에 정의된 것.
- 페이지를 처리하고 표시하는 역할 담당
- 대안: JQUERY사용하면 편함.
- 크로스 오리진 리소스 공유
- 브라우저는 서버와 통신할 때마다 서로에 대한 정보를 HTTP헤더를 이용해 전달
- CORS(cross origin resource sharing)은 HTTP헤더에 추가적으로 정보를 추가해 브라우저와 서버가 서로 통신을 해야한다는 사실을 알게한다.
- 최신버전의 브라우저에만 동작.
- 웹 서버의 프록시 파일
# JSONP 동작원리
- parse()메서드나 stringify()메서드를 사용할 필요 없음.
- 데이터가 문자열 아니고 스크립트파일로 바로 전달되어 이미 객체취급 가능.
- 데이터 리턴할때 이를 처리할 함수 이름 지정할 수도 있다.
- http://example.org/jsonp.php?callback=showEvents
- p.386 참고
//브라우저
<script>
function showEvents(data) { //서버가 전송한 JSON데이터를 처리할 함수
//데이터를 처리하고 페이지에 출력할 코드 작성
}
</script>
<script src="http://example.org/jsonp"></script> //원격서버로부터 json데이터를 요청할 경로
//서버
//서버응답->스크립트는 데이터를처리할 함수(showEvents())를 호출하는 스크립트 전달.
//이 함수 호출이 jsonP의 P다.(padding)
showEvents({
"events": [
{
"location": "샌프란시스코",
"date": 5,
"booking": true
} ...
]
})
# jQuery와 ajax
- jQuery는 서버로부터 리턴된 데이터를 손쉽게 처리할 수 있는 jqXHR객체를 제공함.
- 요청
- .load(): 요소에 HTML코드를 로드. 데이터를 조회하는 가장 간단한 메서드
$.get(url[, data][, callback][, type])
: HTTP GET메서드를 이용해 데이터를 로드. 서버에 데이터를 요청하기 위해 사용.$.post(url[, data][, callback][, type])
: HTTP POST로 데이터를 로드. 서버에 저장된 데이터 수정위해 새로운 데이터를 전달할 때 사용.$.getJSON(url[, data][, callback])
: GET요청 이용해 JSON데이터를 로드한다. 서버가 JSON데이터 리턴할 때 사용.$.getScript(url[, callback])
: GET요청 이용해 스크립트를 로드하고 실행. js데이터(e.g JSONP)를 로드할 때 사용.$.ajax()
: 모든 요청 수행가능. 위에 설명한 메서드들은 내부적으로 이 메서드 사용.- => url: 데이터 가져올 경로 / data:서버로 전송될 추가정보 / callback: 서버로부터 데이터가 전달되었을 때 호출될 콜백 / type:클라이언트가 원하는 서버의 응답형식
- 응답
- jqXHR속성
- rsponseText: 서버로부터 리턴된 텍스트 데이터를 가져옴.
- responseXML: 서버로부터 리턴된 XML데이터를 가져옴.
- status: 상태 코드를 가져온다.
- statusText: 상태 설명 문자열(주로 오류났을때 상세오류내용 가져옴)
- jqXHR메서드
- .done(): 요청이 성공적으로 처리되었을 때 실행될 코드
- .fail(): 요청이 실패했을 때 실행될 코드
- .always(): 요청의 성공/실패 여부에 관계없이 항상 실행될 코드
- .abort(): 서버와의 커뮤니케이션을 취소.
- jqXHR속성
# jQuery로 HTML을 페이지에 로드하기
- 가장 간단한 메서드.
- 서버로부터 HTML을 로드할 때만 사용하지만, 서버가 응답을 제공하면 그 HTML은 jQuery객체집합에 자동으로 적용
$('#content').load('jq-ajax3.html #content');
- #content를 로드한다 이 url로 #content에만 로드 (페이지 전체가 아닌 일부만 로드하도록 할 수 있다.)
$('nav a').on('click', function(e) {
e.preventDefault(); //새로운 페이지로 이동하는 기본동작 취소
var url = this.href; //url변수에 로드할 페이지의 url저장
$('nav a.current').removeClass('current');
$(this).addClass('current');
$('#container').remove(); //이전 페이지 컨텐츠 제거
$('#conent').load(url + ' #content').hide().fadeIn(slow);
})
# jQuery Ajax 데이터 전송하기
$('#selector a').on('click', function(e) {
e.preventDefault(); //링크에 의해 다른 페이지로 이동하지 않도록!
var queryString = 'vote=' + $(e.target).attr('id'); //e.g. 'vote=grey'
$.get('votes.php', queryString, function(data) {
$('#selector').html(data);
});
});
# Ajax로 폼 전송하기
$('#reister'.on('submit', function(e) {
e.preventDefault(); //form전송을 취소
var details = $('#register').serialize(); //폼 데이터를 수집하고 details로 저장
$.post('register.php', details, function(data) {
$('#register').html(data);
});
});
# JSON로드하기 및 Ajax오류 처리하기
- JSON데이터를 로드하려면 현재 페이지를 제공하는 서버와 같은 서버로부터 JSON데이터를 조회하는 $.getJSON()메서드를 사용하면 된다.JSONP는 $.getScript()
function loadRates(){
$.getJSON('data/rates.json') //getJSON하고 바로 체이닝으로 done, fail, always
.done(function(data){ //데이터를 성공적으로 로드한 경우에만 호출
var d = new Date();
...
$.each(data, function(key, val){
msg += '<div class="' + key + ...
});
$('#rates').html(msg);
}).fail(function(){ //데이터 못가져왔을때만 호출
var msg = '<h2>환율 정보</h2>';
msg += "로드하지 못했슴다";
$('#rates').html(msg);
}).always(function() { //항상 실행.
var reload = '<a id="refresh" href="#">'; //새로고침 링크 추가
$('#reload').html(reload);
$('#refresh').on('click', function(e){ //새로고침 누르면 다시 loadRates실행
e.preventDefault();
loadRates();
});
});
}
# Ajax요청 상세하게 제어하기
$('nav a').on('click', function(e){
e.preventDefault();
var url = this.href;
var $content = $('#content');
...
$.ajax({
type: "POST",
url: url,
timeout: 2000,
beforeSend: function() {
$content.append('로드 중');
},
complete: function() {
$('#loading').remove();
},
success: function() {
$content.html($(data).find('#container')).hide().fadeIn(400);
},
fail: function() {
$('#panel'). ...
}
});
});